diff --git a/dist/vis.css b/dist/vis.css index 93889d03..e97f3199 100644 --- a/dist/vis.css +++ b/dist/vis.css @@ -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; } diff --git a/dist/vis.js b/dist/vis.js index 61f3415d..f62b1468 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -5,7 +5,7 @@ * A dynamic, browser-based visualization library. * * @version 4.15.2-SNAPSHOT - * @date 2016-03-19 + * @date 2016-03-15 * * @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); } @@ -11052,15 +11058,20 @@ return /******/ (function(modules) { // webpackBootstrap var start = getStart(item); var end = getEnd(item); - 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 +11082,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 +11137,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 +15824,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 +15907,7 @@ return /******/ (function(modules) { // webpackBootstrap // default options this.defaultOptions = { + rtl: false, start: null, end: null, moment: moment, @@ -15899,7 +15920,6 @@ return /******/ (function(modules) { // webpackBootstrap zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000 // milliseconds }; this.options = util.extend({}, this.defaultOptions); - this.props = { touch: {} }; @@ -15941,7 +15961,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 +16283,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 +16391,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 +16427,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 +16472,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 +16510,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 +17358,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 +17667,6 @@ 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); - var animation = options && options.animation !== undefined ? options.animation : true; this.range.setRange(min, max, animation); }; @@ -18170,8 +18214,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 +18418,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 +18496,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 +18681,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 +18701,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 +18748,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 +18804,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 +19428,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 +19457,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 +19464,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 +19489,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 +19519,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 +19532,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 +19916,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 +21079,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 +21096,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 +21538,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 +21558,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 +21611,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 +21647,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 +21747,6 @@ return /******/ (function(modules) { // webpackBootstrap this.dirty = false; } - this._repaintDeleteButton(dom.box); this._repaintDragLeft(); this._repaintDragRight(); @@ -21676,7 +21791,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 +21806,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 +21818,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 +21865,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'; + } } }; @@ -21832,6 +21976,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 +22103,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 +22346,7 @@ return /******/ (function(modules) { // webpackBootstrap height: 0 } }; - + this.options = options; // validate data if (data) { if (data.start == undefined) { @@ -22340,27 +22490,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 +22615,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 +22709,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 +22722,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 +22764,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.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'; + } }; /** @@ -22591,7 +22784,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 +22804,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 +23107,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 +23211,6 @@ return /******/ (function(modules) { // webpackBootstrap } else { this.body.dom.backgroundVertical.appendChild(background); } - return this._isResized() || parentChanged; }; @@ -23172,7 +23363,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 +23403,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 +23439,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 +23477,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 +24186,7 @@ return /******/ (function(modules) { // webpackBootstrap // default options this.defaultOptions = { + rtl: false, showCurrentTime: true, moment: moment, @@ -24020,7 +24235,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 +24270,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 +24381,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 +24499,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 +26173,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); } } @@ -29104,7 +29325,9 @@ return /******/ (function(modules) { // webpackBootstrap value: function create(properties) { var constructorClass = arguments.length <= 1 || arguments[1] === undefined ? _Node2.default : arguments[1]; - return new constructorClass(properties, this.body, this.images, this.groups, this.options); + var idField = this.body.data.nodes._fieldId; + var id = properties[idField]; + return new constructorClass(id, properties, this.body, this.images, this.groups, this.options); } }, { key: 'refresh', @@ -29365,9 +29588,9 @@ return /******/ (function(modules) { // webpackBootstrap /** * @class Node * A node. A node can be connected to other nodes via one or multiple edges. + * @param {string} id Id for the node * @param {object} options An object containing options for the node. All - * options are optional, except for the id. - * {number} id Id of the node. Required + * options are optional * {string} label Text label for the node * {number} x Horizontal position of the node * {number} y Vertical position of the node @@ -29389,7 +29612,7 @@ return /******/ (function(modules) { // webpackBootstrap */ var Node = function () { - function Node(options, body, imagelist, grouplist, globalOptions) { + function Node(id, options, body, imagelist, grouplist, globalOptions) { _classCallCheck(this, Node); this.options = util.bridgeObject(globalOptions); @@ -29398,8 +29621,11 @@ return /******/ (function(modules) { // webpackBootstrap this.edges = []; // all edges connected to this node - // set defaults for the options - this.id = undefined; + if (id === undefined) { + throw "Node must have an id"; + } + + this.id = id; this.imagelist = imagelist; this.grouplist = grouplist; @@ -29457,14 +29683,6 @@ return /******/ (function(modules) { // webpackBootstrap if (!options) { return; } - // basic options - if (options.id !== undefined) { - this.id = options.id; - } - - if (this.id === undefined) { - throw "Node must have an id"; - } // set these options locally // clear x and y positions @@ -32139,7 +32357,9 @@ return /******/ (function(modules) { // webpackBootstrap }, { key: 'create', value: function create(properties) { - return new _Edge2.default(properties, this.body, this.options); + var idField = this.body.data.edges._fieldId; + var id = properties[idField]; + return new _Edge2.default(id, properties, this.body, this.options); } }, { key: 'markAllEdgesAsDirty', @@ -32242,6 +32462,7 @@ return /******/ (function(modules) { // webpackBootstrap * @class Edge * * A edge connects two nodes + * @param {string} [id] Id for the edge. optional * @param {Object} properties Object with options. Must contain * At least options from and to. * Available options: from (number), @@ -32255,7 +32476,7 @@ return /******/ (function(modules) { // webpackBootstrap */ var Edge = function () { - function Edge(options, body, globalOptions) { + function Edge(id, options, body, globalOptions) { _classCallCheck(this, Edge); if (body === undefined) { @@ -32266,7 +32487,7 @@ return /******/ (function(modules) { // webpackBootstrap this.body = body; // initialize variables - this.id = undefined; + this.id = id; this.fromId = undefined; this.toId = undefined; this.selected = false; @@ -32306,9 +32527,6 @@ return /******/ (function(modules) { // webpackBootstrap Edge.parseOptions(this.options, options, true, this.globalOptions); - if (options.id !== undefined) { - this.id = options.id; - } if (options.from !== undefined) { this.fromId = options.from; } @@ -32388,14 +32606,14 @@ return /******/ (function(modules) { // webpackBootstrap if (this.options.smooth.enabled === true) { if (this.options.smooth.type === 'dynamic') { dataChanged = true; - this.edgeType = new _BezierEdgeDynamic2.default(this.options, this.body, this.labelModule); + this.edgeType = new _BezierEdgeDynamic2.default(this.id, this.options, this.body, this.labelModule); } else if (this.options.smooth.type === 'cubicBezier') { - this.edgeType = new _CubicBezierEdge2.default(this.options, this.body, this.labelModule); + this.edgeType = new _CubicBezierEdge2.default(this.id, this.options, this.body, this.labelModule); } else { - this.edgeType = new _BezierEdgeStatic2.default(this.options, this.body, this.labelModule); + this.edgeType = new _BezierEdgeStatic2.default(this.id, this.options, this.body, this.labelModule); } } else { - this.edgeType = new _StraightEdge2.default(this.options, this.body, this.labelModule); + this.edgeType = new _StraightEdge2.default(this.id, this.options, this.body, this.labelModule); } } else { // if nothing changes, we just set the options. @@ -32843,10 +33061,10 @@ return /******/ (function(modules) { // webpackBootstrap var CubicBezierEdge = function (_CubicBezierEdgeBase) { _inherits(CubicBezierEdge, _CubicBezierEdgeBase); - function CubicBezierEdge(options, body, labelModule) { + function CubicBezierEdge(id, options, body, labelModule) { _classCallCheck(this, CubicBezierEdge); - return _possibleConstructorReturn(this, Object.getPrototypeOf(CubicBezierEdge).call(this, options, body, labelModule)); + return _possibleConstructorReturn(this, Object.getPrototypeOf(CubicBezierEdge).call(this, id, options, body, labelModule)); } /** @@ -32991,10 +33209,10 @@ return /******/ (function(modules) { // webpackBootstrap var CubicBezierEdgeBase = function (_BezierEdgeBase) { _inherits(CubicBezierEdgeBase, _BezierEdgeBase); - function CubicBezierEdgeBase(options, body, labelModule) { + function CubicBezierEdgeBase(id, options, body, labelModule) { _classCallCheck(this, CubicBezierEdgeBase); - return _possibleConstructorReturn(this, Object.getPrototypeOf(CubicBezierEdgeBase).call(this, options, body, labelModule)); + return _possibleConstructorReturn(this, Object.getPrototypeOf(CubicBezierEdgeBase).call(this, id, options, body, labelModule)); } /** @@ -33077,10 +33295,10 @@ return /******/ (function(modules) { // webpackBootstrap var BezierEdgeBase = function (_EdgeBase) { _inherits(BezierEdgeBase, _EdgeBase); - function BezierEdgeBase(options, body, labelModule) { + function BezierEdgeBase(id, options, body, labelModule) { _classCallCheck(this, BezierEdgeBase); - return _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeBase).call(this, options, body, labelModule)); + return _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeBase).call(this, id, options, body, labelModule)); } /** @@ -33213,9 +33431,10 @@ return /******/ (function(modules) { // webpackBootstrap var util = __webpack_require__(1); var EdgeBase = function () { - function EdgeBase(options, body, labelModule) { + function EdgeBase(id, options, body, labelModule) { _classCallCheck(this, EdgeBase); + this.id = id; this.body = body; this.labelModule = labelModule; this.options = {}; @@ -33245,7 +33464,6 @@ return /******/ (function(modules) { // webpackBootstrap this.options = options; this.from = this.body.nodes[this.options.from]; this.to = this.body.nodes[this.options.to]; - this.id = this.options.id; } /** @@ -33819,12 +34037,12 @@ return /******/ (function(modules) { // webpackBootstrap var BezierEdgeDynamic = function (_BezierEdgeBase) { _inherits(BezierEdgeDynamic, _BezierEdgeBase); - function BezierEdgeDynamic(options, body, labelModule) { + function BezierEdgeDynamic(id, options, body, labelModule) { _classCallCheck(this, BezierEdgeDynamic); // --> this calls the setOptions below - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeDynamic).call(this, options, body, labelModule)); + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeDynamic).call(this, id, options, body, labelModule)); //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked. @@ -33846,7 +34064,6 @@ return /******/ (function(modules) { // webpackBootstrap // set the options and the to and from nodes this.options = options; - this.id = this.options.id; this.from = this.body.nodes[this.options.from]; this.to = this.body.nodes[this.options.to]; @@ -33907,12 +34124,14 @@ return /******/ (function(modules) { // webpackBootstrap value: function setupSupportNode() { if (this.via === undefined) { var nodeId = "edgeId:" + this.id; - var node = this.body.functions.createNode({ - id: nodeId, + var properties = { shape: 'circle', physics: true, hidden: true - }); + }; + var idField = this.body.data.nodes._fieldId; + properties[idField] = nodeId; + var node = this.body.functions.createNode(properties); this.body.nodes[nodeId] = node; this.via = node; this.via.parentEdgeId = this.id; @@ -34024,10 +34243,10 @@ return /******/ (function(modules) { // webpackBootstrap var BezierEdgeStatic = function (_BezierEdgeBase) { _inherits(BezierEdgeStatic, _BezierEdgeBase); - function BezierEdgeStatic(options, body, labelModule) { + function BezierEdgeStatic(id, options, body, labelModule) { _classCallCheck(this, BezierEdgeStatic); - return _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeStatic).call(this, options, body, labelModule)); + return _possibleConstructorReturn(this, Object.getPrototypeOf(BezierEdgeStatic).call(this, id, options, body, labelModule)); } /** @@ -42694,8 +42913,9 @@ return /******/ (function(modules) { // webpackBootstrap key: '_getNewTargetNode', value: function _getNewTargetNode(x, y) { var controlNodeStyle = util.deepExtend({}, this.options.controlNodeStyle); + var idField = this.body.data.nodes._fieldId; - controlNodeStyle.id = 'targetNode' + util.randomUUID(); + controlNodeStyle[idField] = 'targetNode' + util.randomUUID(); controlNodeStyle.hidden = false; controlNodeStyle.physics = false; controlNodeStyle.x = x; @@ -42865,7 +43085,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)); } @@ -43256,11 +43481,12 @@ return /******/ (function(modules) { // webpackBootstrap var _this5 = this; var defaultData = { - id: util.randomUUID(), x: clickData.pointer.canvas.x, y: clickData.pointer.canvas.y, label: 'new' }; + var idField = this.body.data.nodes._fieldId; + defaultData[idField] = util.randomUUID(); if (typeof this.options.addNode === 'function') { if (this.options.addNode.length === 2) { diff --git a/dist/vis.min.css b/dist/vis.min.css index d7e4286c..40d182cf 100644 --- a/dist/vis.min.css +++ b/dist/vis.min.css @@ -1 +1 @@ -.vis-background,.vis-labelset,.vis-timeline{overflow:hidden}.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis [class*=span]{min-height:0;width:auto}div.vis-configuration{position:relative;display:block;float:left;font-size:12px}div.vis-configuration-wrapper{display:block;width:700px}div.vis-configuration-wrapper::after{clear:both;content:"";display:block}div.vis-configuration.vis-config-option-container{display:block;width:495px;background-color:#fff;border:2px solid #f7f8fa;border-radius:4px;margin-top:20px;left:10px;padding-left:5px}div.vis-configuration.vis-config-button{display:block;width:495px;height:25px;vertical-align:middle;line-height:25px;background-color:#f7f8fa;border:2px solid #ceced0;border-radius:4px;margin-top:20px;left:10px;padding-left:5px;cursor:pointer;margin-bottom:30px}div.vis-configuration.vis-config-button.hover{background-color:#4588e6;border:2px solid #214373;color:#fff}div.vis-configuration.vis-config-item{display:block;float:left;width:495px;height:25px;vertical-align:middle;line-height:25px}div.vis-configuration.vis-config-item.vis-config-s2{left:10px;background-color:#f7f8fa;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s3{left:20px;background-color:#e4e9f0;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s4{left:30px;background-color:#cfd8e6;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-header{font-size:18px;font-weight:700}div.vis-configuration.vis-config-label{width:120px;height:25px;line-height:25px}div.vis-configuration.vis-config-label.vis-config-s3{width:110px}div.vis-configuration.vis-config-label.vis-config-s4{width:100px}div.vis-configuration.vis-config-colorBlock{top:1px;width:30px;height:19px;border:1px solid #444;border-radius:2px;padding:0;margin:0;cursor:pointer}input.vis-configuration.vis-config-checkbox{left:-5px}input.vis-configuration.vis-config-rangeinput{position:relative;top:-5px;width:60px;padding:1px;margin:0;pointer-events:none}.vis-panel,.vis-timeline{padding:0;box-sizing:border-box}input.vis-configuration.vis-config-range{-webkit-appearance:none;border:0 solid #fff;background-color:rgba(0,0,0,0);width:300px;height:20px}input.vis-configuration.vis-config-range::-webkit-slider-runnable-track{width:300px;height:5px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0 );border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-webkit-slider-thumb{-webkit-appearance:none;border:1px solid #14334b;height:17px;width:17px;border-radius:50%;background:#3876c2;background:-moz-linear-gradient(top,#3876c2 0,#385380 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3876c2),color-stop(100%,#385380));background:-webkit-linear-gradient(top,#3876c2 0,#385380 100%);background:-o-linear-gradient(top,#3876c2 0,#385380 100%);background:-ms-linear-gradient(top,#3876c2 0,#385380 100%);background:linear-gradient(to bottom,#3876c2 0,#385380 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3876c2', endColorstr='#385380', GradientType=0 );box-shadow:#111927 0 0 1px 0;margin-top:-7px}input.vis-configuration.vis-config-range:focus{outline:0}input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track{background:#9d9d9d;background:-moz-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#9d9d9d),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-o-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:linear-gradient(to bottom,#9d9d9d 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#9d9d9d', endColorstr='#c8c8c8', GradientType=0 )}input.vis-configuration.vis-config-range::-moz-range-track{width:300px;height:10px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0 );border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-moz-range-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:-moz-focusring{outline:#fff solid 1px;outline-offset:-1px}input.vis-configuration.vis-config-range::-ms-track{width:300px;height:5px;background:0 0;border-color:transparent;border-width:6px 0;color:transparent}input.vis-configuration.vis-config-range::-ms-fill-lower{background:#777;border-radius:10px}input.vis-configuration.vis-config-range::-ms-fill-upper{background:#ddd;border-radius:10px}input.vis-configuration.vis-config-range::-ms-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:focus::-ms-fill-lower{background:#888}input.vis-configuration.vis-config-range:focus::-ms-fill-upper{background:#ccc}.vis-configuration-popup{position:absolute;background:rgba(57,76,89,.85);border:2px solid #f2faff;line-height:30px;height:30px;width:150px;text-align:center;color:#fff;font-size:14px;border-radius:4px;-webkit-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.vis-configuration-popup:after,.vis-configuration-popup:before{left:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.vis-configuration-popup:after{border-color:rgba(136,183,213,0);border-left-color:rgba(57,76,89,.85);border-width:8px;margin-top:-8px}.vis-configuration-popup:before{border-color:rgba(194,225,245,0);border-left-color:#f2faff;border-width:12px;margin-top:-12px}.vis-timeline{position:relative;border:1px solid #bfbfbf;margin:0}.vis-panel{position:absolute;margin:0}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right,.vis-panel.vis-top{border:1px #bfbfbf}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-top{border-left-style:solid;border-right-style:solid}.vis-panel>.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis-itemset,.vis-labelset,.vis-labelset .vis-label{position:relative;box-sizing:border-box}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-labelset .vis-label{left:0;top:0;width:100%;color:#4d4d4d;border-bottom:1px solid #bfbfbf}.vis-labelset .vis-label.draggable{cursor:pointer}.vis-labelset .vis-label:last-child{border-bottom:none}.vis-labelset .vis-label .vis-inner{display:inline-block;padding:5px}.vis-labelset .vis-label .vis-inner.vis-hidden{padding:0}.vis-itemset{padding:0;margin:0}.vis-itemset .vis-background,.vis-itemset .vis-foreground{position:absolute;width:100%;height:100%;overflow:visible}.vis-axis{position:absolute;width:100%;height:0;left:0;z-index:1}.vis-foreground .vis-group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis-foreground .vis-group:last-child{border-bottom:none}.vis-overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block}.vis-item.vis-point.vis-selected,.vis-item.vis-selected{background-color:#FFF785}.vis-item.vis-selected{border-color:#FFC200;z-index:2}.vis-editable.vis-selected{cursor:move}.vis-item.vis-box{text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-point{background:0 0}.vis-item.vis-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis-item.vis-range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis-item.vis-background{border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis-item .vis-item-overflow{position:relative;width:100%;height:100%;padding:0;margin:0;overflow:hidden}.vis-item.vis-range .vis-item-content{position:relative;display:inline-block}.vis-item.vis-background .vis-item-content{position:absolute;display:inline-block}.vis-item.vis-line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis-item .vis-item-content{white-space:nowrap;box-sizing:border-box;padding:5px}.vis-item .vis-delete{background:url(img/timeline/delete.png) center no-repeat;position:absolute;width:24px;height:24px;top:-4px;right:-24px;cursor:pointer}.vis-item.vis-range .vis-drag-left{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;left:-4px;cursor:w-resize}.vis-item.vis-range .vis-drag-right{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;right:-4px;cursor:e-resize}.vis-range.vis-item.vis-readonly .vis-drag-left,.vis-range.vis-item.vis-readonly .vis-drag-right{cursor:auto}.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;border-left:1px solid}.vis-time-axis .vis-grid.vis-minor{border-color:#e5e5e5}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis-current-time{background-color:#FF7F6E;width:2px;z-index:1}.vis-custom-time{background-color:#6E94FF;width:2px;cursor:move;z-index:1}div.vis-network div.vis-close,div.vis-network div.vis-edit-mode div.vis-button,div.vis-network div.vis-manipulation div.vis-button{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor{border-color:#e5e5e5}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major{border-color:#bfbfbf}.vis-data-axis .vis-y-axis.vis-major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-major.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-minor.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis-data-axis .vis-y-axis.vis-title.vis-measure{padding:0;margin:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title.vis-left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis-data-axis .vis-y-axis.vis-title.vis-right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.vis-legend{background-color:rgba(247,252,255,.65);padding:5px;border:1px solid #b3b3b3;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis-legend-text{white-space:nowrap;display:inline-block}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}div.vis-network div.vis-manipulation{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0 );padding-top:4px;position:absolute;left:0;top:0;width:100%;height:28px}div.vis-network div.vis-edit-mode{position:absolute;left:0;top:5px;height:30px}div.vis-network div.vis-close{position:absolute;right:0;top:0;width:30px;height:30px;background-position:20px 3px;background-repeat:no-repeat;background-image:url(img/network/cross.png);user-select:none}div.vis-network div.vis-close:hover{opacity:.6}div.vis-network div.vis-edit-mode div.vis-button,div.vis-network div.vis-manipulation div.vis-button{float:left;font-family:verdana;font-size:12px;-moz-border-radius:15px;border-radius:15px;display:inline-block;background-position:0 0;background-repeat:no-repeat;height:24px;margin-left:10px;padding:0 8px;user-select:none}div.vis-network div.vis-manipulation div.vis-button:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}div.vis-network div.vis-manipulation div.vis-button:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}div.vis-network div.vis-manipulation div.vis-button.vis-back{background-image:url(img/network/backIcon.png)}div.vis-network div.vis-manipulation div.vis-button.vis-none:hover{box-shadow:1px 1px 8px transparent;cursor:default}div.vis-network div.vis-manipulation div.vis-button.vis-none:active{box-shadow:1px 1px 8px transparent}div.vis-network div.vis-manipulation div.vis-button.vis-none{padding:0}div.vis-network div.vis-manipulation div.notification{margin:2px;font-weight:700}div.vis-network div.vis-manipulation div.vis-button.vis-add{background-image:url(img/network/addNodeIcon.png)}div.vis-network div.vis-edit-mode div.vis-button.vis-edit,div.vis-network div.vis-manipulation div.vis-button.vis-edit{background-image:url(img/network/editIcon.png)}div.vis-network div.vis-edit-mode div.vis-button.vis-edit.vis-edit-mode{background-color:#fcfcfc;border:1px solid #ccc}div.vis-network div.vis-manipulation div.vis-button.vis-connect{background-image:url(img/network/connectIcon.png)}div.vis-network div.vis-manipulation div.vis-button.vis-delete{background-image:url(img/network/deleteIcon.png)}div.vis-network div.vis-edit-mode div.vis-label,div.vis-network div.vis-manipulation div.vis-label{margin:0 0 0 23px;line-height:25px}div.vis-network div.vis-manipulation div.vis-separator-line{float:left;display:inline-block;width:1px;height:21px;background-color:#bdbdbd;margin:0 7px 0 15px}div.vis-network-tooltip{position:absolute;visibility:hidden;padding:5px;white-space:nowrap;font-family:verdana;font-size:14px;color:#000;background-color:#f5f4ed;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;border:1px solid #808074;box-shadow:3px 3px 10px rgba(0,0,0,.2);pointer-events:none}div.vis-network div.vis-navigation div.vis-button{width:34px;height:34px;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.vis-network div.vis-navigation div.vis-button:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.vis-network div.vis-navigation div.vis-button:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.vis-network div.vis-navigation div.vis-button.vis-up{background-image:url(img/network/upArrow.png);bottom:50px;left:55px}div.vis-network div.vis-navigation div.vis-button.vis-down{background-image:url(img/network/downArrow.png);bottom:10px;left:55px}div.vis-network div.vis-navigation div.vis-button.vis-left{background-image:url(img/network/leftArrow.png);bottom:10px;left:15px}div.vis-network div.vis-navigation div.vis-button.vis-right{background-image:url(img/network/rightArrow.png);bottom:10px;left:95px}div.vis-network div.vis-navigation div.vis-button.vis-zoomIn{background-image:url(img/network/plus.png);bottom:10px;right:15px}div.vis-network div.vis-navigation div.vis-button.vis-zoomOut{background-image:url(img/network/minus.png);bottom:10px;right:55px}div.vis-network div.vis-navigation div.vis-button.vis-zoomExtends{background-image:url(img/network/zoomExtends.png);bottom:50px;right:15px}div.vis-color-picker{position:absolute;top:0;left:30px;margin-top:-140px;margin-left:30px;width:310px;height:444px;z-index:1;padding:10px;border-radius:15px;background-color:#fff;display:none;box-shadow:rgba(0,0,0,.5) 0 0 10px 0}div.vis-color-picker div.vis-arrow{position:absolute;top:147px;left:5px}div.vis-color-picker div.vis-arrow::after,div.vis-color-picker div.vis-arrow::before{right:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.vis-color-picker div.vis-arrow:after{border-color:rgba(255,255,255,0);border-right-color:#fff;border-width:30px;margin-top:-30px}div.vis-color-picker div.vis-color{position:absolute;width:289px;height:289px;cursor:pointer}div.vis-color-picker div.vis-brightness{position:absolute;top:313px}div.vis-color-picker div.vis-opacity{position:absolute;top:350px}div.vis-color-picker div.vis-selector{position:absolute;top:137px;left:137px;width:15px;height:15px;border-radius:15px;border:1px solid #fff;background:#4c4c4c;background:-moz-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4c4c4c),color-stop(12%,#595959),color-stop(25%,#666),color-stop(39%,#474747),color-stop(50%,#2c2c2c),color-stop(51%,#000),color-stop(60%,#111),color-stop(76%,#2b2b2b),color-stop(91%,#1c1c1c),color-stop(100%,#131313));background:-webkit-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-o-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-ms-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:linear-gradient(to bottom,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313', GradientType=0 )}div.vis-color-picker div.vis-initial-color,div.vis-color-picker div.vis-new-color{width:140px;height:20px;top:380px;font-size:10px;color:rgba(0,0,0,.4);line-height:20px;position:absolute;vertical-align:middle}div.vis-color-picker div.vis-new-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:159px;text-align:right;padding-right:2px}div.vis-color-picker div.vis-initial-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:10px;text-align:left;padding-left:2px}div.vis-color-picker div.vis-label{position:absolute;width:300px;left:10px}div.vis-color-picker div.vis-label.vis-brightness{top:300px}div.vis-color-picker div.vis-label.vis-opacity{top:338px}div.vis-color-picker div.vis-button{position:absolute;width:68px;height:25px;border-radius:10px;vertical-align:middle;text-align:center;line-height:25px;top:410px;border:2px solid #d9d9d9;background-color:#f7f7f7;cursor:pointer}div.vis-color-picker div.vis-button.vis-cancel{left:5px}div.vis-color-picker div.vis-button.vis-load{left:82px}div.vis-color-picker div.vis-button.vis-apply{left:159px}div.vis-color-picker div.vis-button.vis-save{left:236px}div.vis-color-picker input.vis-range{width:290px;height:20px} \ No newline at end of file +.vis-background,.vis-labelset,.vis-timeline{overflow:hidden}.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis [class*=span]{min-height:0;width:auto}div.vis-configuration{position:relative;display:block;float:left;font-size:12px}div.vis-configuration-wrapper{display:block;width:700px}div.vis-configuration-wrapper::after{clear:both;content:"";display:block}div.vis-configuration.vis-config-option-container{display:block;width:495px;background-color:#fff;border:2px solid #f7f8fa;border-radius:4px;margin-top:20px;left:10px;padding-left:5px}div.vis-configuration.vis-config-button{display:block;width:495px;height:25px;vertical-align:middle;line-height:25px;background-color:#f7f8fa;border:2px solid #ceced0;border-radius:4px;margin-top:20px;left:10px;padding-left:5px;cursor:pointer;margin-bottom:30px}div.vis-configuration.vis-config-button.hover{background-color:#4588e6;border:2px solid #214373;color:#fff}div.vis-configuration.vis-config-item{display:block;float:left;width:495px;height:25px;vertical-align:middle;line-height:25px}div.vis-configuration.vis-config-item.vis-config-s2{left:10px;background-color:#f7f8fa;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s3{left:20px;background-color:#e4e9f0;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s4{left:30px;background-color:#cfd8e6;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-header{font-size:18px;font-weight:700}div.vis-configuration.vis-config-label{width:120px;height:25px;line-height:25px}div.vis-configuration.vis-config-label.vis-config-s3{width:110px}div.vis-configuration.vis-config-label.vis-config-s4{width:100px}div.vis-configuration.vis-config-colorBlock{top:1px;width:30px;height:19px;border:1px solid #444;border-radius:2px;padding:0;margin:0;cursor:pointer}input.vis-configuration.vis-config-checkbox{left:-5px}input.vis-configuration.vis-config-rangeinput{position:relative;top:-5px;width:60px;padding:1px;margin:0;pointer-events:none}.vis-panel,.vis-timeline{padding:0;box-sizing:border-box}input.vis-configuration.vis-config-range{-webkit-appearance:none;border:0 solid #fff;background-color:rgba(0,0,0,0);width:300px;height:20px}input.vis-configuration.vis-config-range::-webkit-slider-runnable-track{width:300px;height:5px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0 );border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-webkit-slider-thumb{-webkit-appearance:none;border:1px solid #14334b;height:17px;width:17px;border-radius:50%;background:#3876c2;background:-moz-linear-gradient(top,#3876c2 0,#385380 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3876c2),color-stop(100%,#385380));background:-webkit-linear-gradient(top,#3876c2 0,#385380 100%);background:-o-linear-gradient(top,#3876c2 0,#385380 100%);background:-ms-linear-gradient(top,#3876c2 0,#385380 100%);background:linear-gradient(to bottom,#3876c2 0,#385380 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#3876c2', endColorstr='#385380', GradientType=0 );box-shadow:#111927 0 0 1px 0;margin-top:-7px}input.vis-configuration.vis-config-range:focus{outline:0}input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track{background:#9d9d9d;background:-moz-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#9d9d9d),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-o-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#9d9d9d 0,#c8c8c8 99%);background:linear-gradient(to bottom,#9d9d9d 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#9d9d9d', endColorstr='#c8c8c8', GradientType=0 )}input.vis-configuration.vis-config-range::-moz-range-track{width:300px;height:10px;background:#dedede;background:-moz-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#dedede),color-stop(99%,#c8c8c8));background:-webkit-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-o-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:-ms-linear-gradient(top,#dedede 0,#c8c8c8 99%);background:linear-gradient(to bottom,#dedede 0,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8', GradientType=0 );border:1px solid #999;box-shadow:#aaa 0 0 3px 0;border-radius:3px}input.vis-configuration.vis-config-range::-moz-range-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:-moz-focusring{outline:#fff solid 1px;outline-offset:-1px}input.vis-configuration.vis-config-range::-ms-track{width:300px;height:5px;background:0 0;border-color:transparent;border-width:6px 0;color:transparent}input.vis-configuration.vis-config-range::-ms-fill-lower{background:#777;border-radius:10px}input.vis-configuration.vis-config-range::-ms-fill-upper{background:#ddd;border-radius:10px}input.vis-configuration.vis-config-range::-ms-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:focus::-ms-fill-lower{background:#888}input.vis-configuration.vis-config-range:focus::-ms-fill-upper{background:#ccc}.vis-configuration-popup{position:absolute;background:rgba(57,76,89,.85);border:2px solid #f2faff;line-height:30px;height:30px;width:150px;text-align:center;color:#fff;font-size:14px;border-radius:4px;-webkit-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.vis-configuration-popup:after,.vis-configuration-popup:before{left:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.vis-configuration-popup:after{border-color:rgba(136,183,213,0);border-left-color:rgba(57,76,89,.85);border-width:8px;margin-top:-8px}.vis-configuration-popup:before{border-color:rgba(194,225,245,0);border-left-color:#f2faff;border-width:12px;margin-top:-12px}.vis-timeline{position:relative;border:1px solid #bfbfbf;margin:0}.vis-panel{position:absolute;margin:0}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right,.vis-panel.vis-top{border:1px #bfbfbf}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis-panel.vis-bottom,.vis-panel.vis-center,.vis-panel.vis-top{border-left-style:solid;border-right-style:solid}.vis-panel>.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis-itemset,.vis-labelset,.vis-labelset .vis-label{position:relative;box-sizing:border-box}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-labelset .vis-label{left:0;top:0;width:100%;color:#4d4d4d;border-bottom:1px solid #bfbfbf}.vis-labelset .vis-label.draggable{cursor:pointer}.vis-labelset .vis-label:last-child{border-bottom:none}.vis-labelset .vis-label .vis-inner{display:inline-block;padding:5px}.vis-labelset .vis-label .vis-inner.vis-hidden{padding:0}.vis-itemset{padding:0;margin:0}.vis-itemset .vis-background,.vis-itemset .vis-foreground{position:absolute;width:100%;height:100%;overflow:visible}.vis-axis{position:absolute;width:100%;height:0;left:0;z-index:1}.vis-foreground .vis-group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis-foreground .vis-group:last-child{border-bottom:none}.vis-overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block}.vis-item.vis-point.vis-selected,.vis-item.vis-selected{background-color:#FFF785}.vis-item.vis-selected{border-color:#FFC200;z-index:2}.vis-editable.vis-selected{cursor:move}.vis-item.vis-box{text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-point{background:0 0}.vis-item.vis-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis-item.vis-range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis-item.vis-background{border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis-item .vis-item-overflow{position:relative;width:100%;height:100%;padding:0;margin:0;overflow:hidden}.vis-item .vis-delete,.vis-item .vis-delete-rtl{background:url(img/timeline/delete.png) center no-repeat;height:24px;top:-4px;cursor:pointer}.vis-item.vis-range .vis-item-content{position:relative;display:inline-block}.vis-item.vis-background .vis-item-content{position:absolute;display:inline-block}.vis-item.vis-line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis-item .vis-item-content{white-space:nowrap;box-sizing:border-box;padding:5px}.vis-item .vis-delete{position:absolute;width:24px;right:-24px}.vis-item .vis-delete-rtl{position:absolute;width:24px;left:-24px}.vis-item.vis-range .vis-drag-left{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;left:-4px;cursor:w-resize}.vis-item.vis-range .vis-drag-right{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;right:-4px;cursor:e-resize}.vis-range.vis-item.vis-readonly .vis-drag-left,.vis-range.vis-item.vis-readonly .vis-drag-right{cursor:auto}.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;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}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis-current-time{background-color:#FF7F6E;width:2px;z-index:1}.vis-custom-time{background-color:#6E94FF;width:2px;cursor:move;z-index:1}div.vis-network div.vis-close,div.vis-network div.vis-edit-mode div.vis-button,div.vis-network div.vis-manipulation div.vis-button{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-touch-callout:none;-khtml-user-select:none}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor{border-color:#e5e5e5}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major{border-color:#bfbfbf}.vis-data-axis .vis-y-axis.vis-major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-major.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-minor.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis-data-axis .vis-y-axis.vis-title.vis-measure{padding:0;margin:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title.vis-left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis-data-axis .vis-y-axis.vis-title.vis-right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.vis-legend{background-color:rgba(247,252,255,.65);padding:5px;border:1px solid #b3b3b3;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis-legend-text{white-space:nowrap;display:inline-block}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}div.vis-network div.vis-manipulation{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0 );padding-top:4px;position:absolute;left:0;top:0;width:100%;height:28px}div.vis-network div.vis-edit-mode{position:absolute;left:0;top:5px;height:30px}div.vis-network div.vis-close{position:absolute;right:0;top:0;width:30px;height:30px;background-position:20px 3px;background-repeat:no-repeat;background-image:url(img/network/cross.png);user-select:none}div.vis-network div.vis-close:hover{opacity:.6}div.vis-network div.vis-edit-mode div.vis-button,div.vis-network div.vis-manipulation div.vis-button{float:left;font-family:verdana;font-size:12px;-moz-border-radius:15px;border-radius:15px;display:inline-block;background-position:0 0;background-repeat:no-repeat;height:24px;margin-left:10px;padding:0 8px;user-select:none}div.vis-network div.vis-manipulation div.vis-button:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}div.vis-network div.vis-manipulation div.vis-button:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}div.vis-network div.vis-manipulation div.vis-button.vis-back{background-image:url(img/network/backIcon.png)}div.vis-network div.vis-manipulation div.vis-button.vis-none:hover{box-shadow:1px 1px 8px transparent;cursor:default}div.vis-network div.vis-manipulation div.vis-button.vis-none:active{box-shadow:1px 1px 8px transparent}div.vis-network div.vis-manipulation div.vis-button.vis-none{padding:0}div.vis-network div.vis-manipulation div.notification{margin:2px;font-weight:700}div.vis-network div.vis-manipulation div.vis-button.vis-add{background-image:url(img/network/addNodeIcon.png)}div.vis-network div.vis-edit-mode div.vis-button.vis-edit,div.vis-network div.vis-manipulation div.vis-button.vis-edit{background-image:url(img/network/editIcon.png)}div.vis-network div.vis-edit-mode div.vis-button.vis-edit.vis-edit-mode{background-color:#fcfcfc;border:1px solid #ccc}div.vis-network div.vis-manipulation div.vis-button.vis-connect{background-image:url(img/network/connectIcon.png)}div.vis-network div.vis-manipulation div.vis-button.vis-delete{background-image:url(img/network/deleteIcon.png)}div.vis-network div.vis-edit-mode div.vis-label,div.vis-network div.vis-manipulation div.vis-label{margin:0 0 0 23px;line-height:25px}div.vis-network div.vis-manipulation div.vis-separator-line{float:left;display:inline-block;width:1px;height:21px;background-color:#bdbdbd;margin:0 7px 0 15px}div.vis-network-tooltip{position:absolute;visibility:hidden;padding:5px;white-space:nowrap;font-family:verdana;font-size:14px;color:#000;background-color:#f5f4ed;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;border:1px solid #808074;box-shadow:3px 3px 10px rgba(0,0,0,.2);pointer-events:none}div.vis-network div.vis-navigation div.vis-button{width:34px;height:34px;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.vis-network div.vis-navigation div.vis-button:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.vis-network div.vis-navigation div.vis-button:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.vis-network div.vis-navigation div.vis-button.vis-up{background-image:url(img/network/upArrow.png);bottom:50px;left:55px}div.vis-network div.vis-navigation div.vis-button.vis-down{background-image:url(img/network/downArrow.png);bottom:10px;left:55px}div.vis-network div.vis-navigation div.vis-button.vis-left{background-image:url(img/network/leftArrow.png);bottom:10px;left:15px}div.vis-network div.vis-navigation div.vis-button.vis-right{background-image:url(img/network/rightArrow.png);bottom:10px;left:95px}div.vis-network div.vis-navigation div.vis-button.vis-zoomIn{background-image:url(img/network/plus.png);bottom:10px;right:15px}div.vis-network div.vis-navigation div.vis-button.vis-zoomOut{background-image:url(img/network/minus.png);bottom:10px;right:55px}div.vis-network div.vis-navigation div.vis-button.vis-zoomExtends{background-image:url(img/network/zoomExtends.png);bottom:50px;right:15px}div.vis-color-picker{position:absolute;top:0;left:30px;margin-top:-140px;margin-left:30px;width:310px;height:444px;z-index:1;padding:10px;border-radius:15px;background-color:#fff;display:none;box-shadow:rgba(0,0,0,.5) 0 0 10px 0}div.vis-color-picker div.vis-arrow{position:absolute;top:147px;left:5px}div.vis-color-picker div.vis-arrow::after,div.vis-color-picker div.vis-arrow::before{right:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}div.vis-color-picker div.vis-arrow:after{border-color:rgba(255,255,255,0);border-right-color:#fff;border-width:30px;margin-top:-30px}div.vis-color-picker div.vis-color{position:absolute;width:289px;height:289px;cursor:pointer}div.vis-color-picker div.vis-brightness{position:absolute;top:313px}div.vis-color-picker div.vis-opacity{position:absolute;top:350px}div.vis-color-picker div.vis-selector{position:absolute;top:137px;left:137px;width:15px;height:15px;border-radius:15px;border:1px solid #fff;background:#4c4c4c;background:-moz-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4c4c4c),color-stop(12%,#595959),color-stop(25%,#666),color-stop(39%,#474747),color-stop(50%,#2c2c2c),color-stop(51%,#000),color-stop(60%,#111),color-stop(76%,#2b2b2b),color-stop(91%,#1c1c1c),color-stop(100%,#131313));background:-webkit-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-o-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:-ms-linear-gradient(top,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);background:linear-gradient(to bottom,#4c4c4c 0,#595959 12%,#666 25%,#474747 39%,#2c2c2c 50%,#000 51%,#111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313', GradientType=0 )}div.vis-color-picker div.vis-initial-color,div.vis-color-picker div.vis-new-color{width:140px;height:20px;top:380px;font-size:10px;color:rgba(0,0,0,.4);line-height:20px;position:absolute;vertical-align:middle}div.vis-color-picker div.vis-new-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:159px;text-align:right;padding-right:2px}div.vis-color-picker div.vis-initial-color{border:1px solid rgba(0,0,0,.1);border-radius:5px;left:10px;text-align:left;padding-left:2px}div.vis-color-picker div.vis-label{position:absolute;width:300px;left:10px}div.vis-color-picker div.vis-label.vis-brightness{top:300px}div.vis-color-picker div.vis-label.vis-opacity{top:338px}div.vis-color-picker div.vis-button{position:absolute;width:68px;height:25px;border-radius:10px;vertical-align:middle;text-align:center;line-height:25px;top:410px;border:2px solid #d9d9d9;background-color:#f7f7f7;cursor:pointer}div.vis-color-picker div.vis-button.vis-cancel{left:5px}div.vis-color-picker div.vis-button.vis-load{left:82px}div.vis-color-picker div.vis-button.vis-apply{left:159px}div.vis-color-picker div.vis-button.vis-save{left:236px}div.vis-color-picker input.vis-range{width:290px;height:20px} \ No newline at end of file diff --git a/docs/data/dataset.html b/docs/data/dataset.html index c143305c..3f90ead4 100644 --- a/docs/data/dataset.html +++ b/docs/data/dataset.html @@ -431,7 +431,7 @@ var data = new vis.DataSet([data] [, options]) Number[] - Update on ore multiple existing items. data 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 Data Manipulation. + Update one or multiple existing items. data 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 Data Manipulation. diff --git a/examples/timeline/groups/groupsEditable.html b/examples/timeline/groups/groupsEditable.html index 8fce1410..25ac3a57 100644 --- a/examples/timeline/groups/groupsEditable.html +++ b/examples/timeline/groups/groupsEditable.html @@ -299,6 +299,7 @@ a.value = b.value; b.value = v; }, + orientation: 'both', editable: true, groupEditable: true, start: new Date(2015, 6, 1), diff --git a/examples/timeline/other/rtl.html b/examples/timeline/other/rtl.html new file mode 100644 index 00000000..63fc79ad --- /dev/null +++ b/examples/timeline/other/rtl.html @@ -0,0 +1,77 @@ + + + + Timeline | RTL example + + + + + + + + + +

An editable timeline allows to drag items around, create new items, and remove items. Changes are logged in the browser console.

+ +
+ + + + \ No newline at end of file diff --git a/lib/network/modules/ManipulationSystem.js b/lib/network/modules/ManipulationSystem.js index 94b8b5f7..1334b397 100644 --- a/lib/network/modules/ManipulationSystem.js +++ b/lib/network/modules/ManipulationSystem.js @@ -689,7 +689,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)); } diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index dc990b1d..3778c72c 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -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,6 @@ 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); - var animation = (options && options.animation !== undefined) ? options.animation : true; this.range.setRange(min, max, animation); }; diff --git a/lib/timeline/Range.js b/lib/timeline/Range.js index 97e690e2..41e500af 100644 --- a/lib/timeline/Range.js +++ b/lib/timeline/Range.js @@ -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) + }; + } } /** diff --git a/lib/timeline/Stack.js b/lib/timeline/Stack.js index e39e10c6..b1b8fb03 100644 --- a/lib/timeline/Stack.js +++ b/lib/timeline/Stack.js @@ -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; }; diff --git a/lib/timeline/Timeline.js b/lib/timeline/Timeline.js index ada7b422..6d4ef175 100644 --- a/lib/timeline/Timeline.js +++ b/lib/timeline/Timeline.js @@ -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); } @@ -424,16 +426,22 @@ Timeline.prototype.getItemRange = function () { var start = getStart(item); var end = getEnd(item); + + 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)); @@ -444,8 +452,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 + } } } } @@ -493,7 +506,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); diff --git a/lib/timeline/component/CurrentTime.js b/lib/timeline/component/CurrentTime.js index ee1c7148..a697a582 100644 --- a/lib/timeline/component/CurrentTime.js +++ b/lib/timeline/component/CurrentTime.js @@ -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 { diff --git a/lib/timeline/component/DataAxis.js b/lib/timeline/component/DataAxis.js index 61055666..67af1974 100644 --- a/lib/timeline/component/DataAxis.js +++ b/lib/timeline/component/DataAxis.js @@ -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); } } diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 8a09e4ae..c11d7cce 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -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; diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js index 27aaee38..373a92f3 100644 --- a/lib/timeline/component/ItemSet.js +++ b/lib/timeline/component/ItemSet.js @@ -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(); diff --git a/lib/timeline/component/TimeAxis.js b/lib/timeline/component/TimeAxis.js index 136179b4..d8043521 100644 --- a/lib/timeline/component/TimeAxis.js +++ b/lib/timeline/component/TimeAxis.js @@ -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; }; diff --git a/lib/timeline/component/css/item.css b/lib/timeline/component/css/item.css index 4e048885..77140861 100644 --- a/lib/timeline/component/css/item.css +++ b/lib/timeline/component/css/item.css @@ -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; diff --git a/lib/timeline/component/css/timeaxis.css b/lib/timeline/component/css/timeaxis.css index a9c72aa2..a2feddbb 100644 --- a/lib/timeline/component/css/timeaxis.css +++ b/lib/timeline/component/css/timeaxis.css @@ -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; } diff --git a/lib/timeline/component/item/BoxItem.js b/lib/timeline/component/item/BoxItem.js index 8c58ca42..4aee6f7f 100644 --- a/lib/timeline/component/item/BoxItem.js +++ b/lib/timeline/component/item/BoxItem.js @@ -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'; + } } }; diff --git a/lib/timeline/component/item/Item.js b/lib/timeline/component/item/Item.js index d25fcb43..ea5c7cbb 100644 --- a/lib/timeline/component/item/Item.js +++ b/lib/timeline/component/item/Item.js @@ -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 diff --git a/lib/timeline/component/item/PointItem.js b/lib/timeline/component/item/PointItem.js index 6238e09e..a05b9982 100644 --- a/lib/timeline/component/item/PointItem.js +++ b/lib/timeline/component/item/PointItem.js @@ -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; diff --git a/lib/timeline/component/item/RangeItem.js b/lib/timeline/component/item/RangeItem.js index e0b36a6f..097501a7 100644 --- a/lib/timeline/component/item/RangeItem.js +++ b/lib/timeline/component/item/RangeItem.js @@ -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,6 @@ RangeItem.prototype.redraw = function() { this.dirty = false; } - this._repaintDeleteButton(dom.box); this._repaintDragLeft(); this._repaintDragRight(); @@ -168,7 +167,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 +182,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 +195,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'; + } } }; diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index acf93a17..0069a3db 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -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, diff --git a/lib/util.js b/lib/util.js index a433075a..ce41023c 100644 --- a/lib/util.js +++ b/lib/util.js @@ -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