From 1043ef0887940f49c8aa970681bb8ae2ad387255 Mon Sep 17 00:00:00 2001 From: Alex de Mulder Date: Wed, 12 Nov 2014 15:59:12 +0100 Subject: [PATCH] removed div id from navigation --- HISTORY.md | 1 + dist/vis.js | 1142 ++++++++++++------------- lib/network/mixins/NavigationMixin.js | 6 +- lib/timeline/component/Group.js | 2 +- 4 files changed, 574 insertions(+), 577 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 066ca314..54e77696 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -18,6 +18,7 @@ http://visjs.org ### Timeline - Added a finishedRedraw event. +- Fixed the disappearing item bug. ## 2014-11-07, version 3.6.4 diff --git a/dist/vis.js b/dist/vis.js index 5702d4b4..698f008c 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -101,33 +101,33 @@ return /******/ (function(modules) { // webpackBootstrap // Timeline exports.Timeline = __webpack_require__(18); - exports.Graph2d = __webpack_require__(41); + exports.Graph2d = __webpack_require__(42); exports.timeline = { DateUtil: __webpack_require__(24), - DataStep: __webpack_require__(44), + DataStep: __webpack_require__(45), Range: __webpack_require__(21), - stack: __webpack_require__(50), + stack: __webpack_require__(33), TimeStep: __webpack_require__(27), components: { items: { Item: __webpack_require__(35), - BackgroundItem: __webpack_require__(38), - BoxItem: __webpack_require__(34), - PointItem: __webpack_require__(36), - RangeItem: __webpack_require__(37) + BackgroundItem: __webpack_require__(39), + BoxItem: __webpack_require__(37), + PointItem: __webpack_require__(38), + RangeItem: __webpack_require__(34) }, Component: __webpack_require__(23), CurrentTime: __webpack_require__(28), CustomTime: __webpack_require__(30), - DataAxis: __webpack_require__(43), - GraphGroup: __webpack_require__(45), + DataAxis: __webpack_require__(44), + GraphGroup: __webpack_require__(46), Group: __webpack_require__(32), - BackgroundGroup: __webpack_require__(33), + BackgroundGroup: __webpack_require__(36), ItemSet: __webpack_require__(31), - Legend: __webpack_require__(49), - LineGraph: __webpack_require__(42), + Legend: __webpack_require__(50), + LineGraph: __webpack_require__(43), TimeAxis: __webpack_require__(26) } }; @@ -13233,7 +13233,7 @@ return /******/ (function(modules) { // webpackBootstrap var CurrentTime = __webpack_require__(28); var CustomTime = __webpack_require__(30); var ItemSet = __webpack_require__(31); - var Activator = __webpack_require__(39); + var Activator = __webpack_require__(40); var DateUtil = __webpack_require__(24); /** @@ -15427,11 +15427,11 @@ return /******/ (function(modules) { // webpackBootstrap var DataView = __webpack_require__(9); var Component = __webpack_require__(23); var Group = __webpack_require__(32); - var BackgroundGroup = __webpack_require__(33); - var BoxItem = __webpack_require__(34); - var PointItem = __webpack_require__(36); - var RangeItem = __webpack_require__(37); - var BackgroundItem = __webpack_require__(38); + var BackgroundGroup = __webpack_require__(36); + var BoxItem = __webpack_require__(37); + var PointItem = __webpack_require__(38); + var RangeItem = __webpack_require__(34); + var BackgroundItem = __webpack_require__(39); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -16896,8 +16896,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var stack = __webpack_require__(50); - var RangeItem = __webpack_require__(37); + var stack = __webpack_require__(33); + var RangeItem = __webpack_require__(34); /** * @constructor Group @@ -17302,7 +17302,7 @@ return /******/ (function(modules) { // webpackBootstrap */ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { var visibleItems = []; - var visibleItemsLookup = {}; + var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems var interval = (range.end - range.start) / 4; var lowerBound = range.start - interval; var upperBound = range.end + interval; @@ -17438,144 +17438,201 @@ return /******/ (function(modules) { // webpackBootstrap /* 33 */ /***/ function(module, exports, __webpack_require__) { - var util = __webpack_require__(1); - var Group = __webpack_require__(32); + // Utility functions for ordering and stacking of items + var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors /** - * @constructor BackgroundGroup - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet + * Order items by their start data + * @param {Item[]} items */ - function BackgroundGroup (groupId, data, itemSet) { - Group.call(this, groupId, data, itemSet); + exports.orderByStart = function(items) { + items.sort(function (a, b) { + return a.data.start - b.data.start; + }); + }; - this.width = 0; - this.height = 0; - this.top = 0; - this.left = 0; - } + /** + * Order items by their end date. If they have no end date, their start date + * is used. + * @param {Item[]} items + */ + exports.orderByEnd = function(items) { + items.sort(function (a, b) { + var aTime = ('end' in a.data) ? a.data.end : a.data.start, + bTime = ('end' in b.data) ? b.data.end : b.data.start; - BackgroundGroup.prototype = Object.create(Group.prototype); + return aTime - bTime; + }); + }; /** - * Repaint this group - * @param {{start: number, end: number}} range + * Adjust vertical positions of the items such that they don't overlap each + * other. + * @param {Item[]} items + * All visible items * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * @param {boolean} [restack=false] Force restacking of all items - * @return {boolean} Returns true if the group is resized + * Margins between items and between items and the axis. + * @param {boolean} [force=false] + * If true, all items will be repositioned. If false (default), only + * items having a top===null will be re-stacked */ - BackgroundGroup.prototype.redraw = function(range, margin, restack) { - var resized = false; + exports.stack = function(items, margin, force) { + var i, iMax; - this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); + if (force) { + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + items[i].top = null; + } + } - // calculate actual size - this.width = this.dom.background.offsetWidth; + // calculate new, non-overlapping positions + for (i = 0, iMax = items.length; i < iMax; i++) { + var item = items[i]; + if (item.stack && item.top === null) { + // initialize top position + item.top = margin.axis; - // apply new height (just always zero for BackgroundGroup - this.dom.background.style.height = '0'; + do { + // TODO: optimize checking for overlap. when there is a gap without items, + // you only need to check for items from the next item on, not from zero + 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)) { + collidingItem = other; + break; + } + } - // update vertical position of items after they are re-stacked and the height of the group is calculated - for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { - var item = this.visibleItems[i]; - item.repositionY(margin); + if (collidingItem != null) { + // There is a collision. Reposition the items above the colliding element + item.top = collidingItem.top + collidingItem.height + margin.item.vertical; + } + } while (collidingItem); + } } - - return resized; }; + /** - * Show this group: attach to the DOM + * Adjust vertical positions of the items without stacking them + * @param {Item[]} items + * All visible items + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * Margins between items and between items and the axis. */ - BackgroundGroup.prototype.show = function() { - if (!this.dom.background.parentNode) { - this.itemSet.dom.background.appendChild(this.dom.background); + exports.nostack = function(items, margin, subgroups) { + var i, iMax, newTop; + + // reset top position of all items + for (i = 0, iMax = items.length; i < iMax; i++) { + if (items[i].data.subgroup !== undefined) { + newTop = margin.axis; + for (var subgroup in subgroups) { + if (subgroups.hasOwnProperty(subgroup)) { + if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { + newTop += subgroups[subgroup].height + margin.item.vertical; + } + } + } + items[i].top = newTop; + } + else { + items[i].top = margin.axis; + } } }; - module.exports = BackgroundGroup; + /** + * Test if the two provided items collide + * The items must have parameters left, width, top, and height. + * @param {Item} a The first item + * @param {Item} b The second item + * @param {{horizontal: number, vertical: number}} margin + * An object containing a horizontal and vertical + * 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); + }; /***/ }, /* 34 */ /***/ function(module, exports, __webpack_require__) { + var Hammer = __webpack_require__(19); var Item = __webpack_require__(35); - var util = __webpack_require__(1); /** - * @constructor BoxItem + * @constructor RangeItem * @extends Item - * @param {Object} data Object containing parameters start + * @param {Object} data Object containing parameters start, end * content, className. * @param {{toScreen: function, toTime: function}} conversion * Conversion functions from time to screen and vice versa * @param {Object} [options] Configuration options - * // TODO: describe available options + * // TODO: describe options */ - function BoxItem (data, conversion, options) { + function RangeItem (data, conversion, options) { this.props = { - dot: { - width: 0, - height: 0 - }, - line: { - width: 0, - height: 0 + content: { + width: 0 } }; + this.overflow = false; // if contents can overflow (css styling), this flag is set to true // validate data if (data) { if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data); + throw new Error('Property "start" missing in item ' + data.id); + } + if (data.end == undefined) { + throw new Error('Property "end" missing in item ' + data.id); } } Item.call(this, data, conversion, options); } - BoxItem.prototype = new Item (null, null, null); + RangeItem.prototype = new Item (null, null, null); + + RangeItem.prototype.baseClassName = 'item range'; /** * Check whether this item is visible inside given range * @returns {{start: Number, end: Number}} range with a timestamp for start and end * @returns {boolean} True if visible */ - BoxItem.prototype.isVisible = function(range) { + RangeItem.prototype.isVisible = function(range) { // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + return (this.data.start < range.end) && (this.data.end > range.start); }; /** * Repaint the item */ - BoxItem.prototype.redraw = function() { + RangeItem.prototype.redraw = function() { var dom = this.dom; if (!dom) { // create DOM this.dom = {}; dom = this.dom; - // create main box - dom.box = document.createElement('DIV'); + // background box + dom.box = document.createElement('div'); + // className is updated in redraw() - // contents box (inside the background box). used for making margins - dom.content = document.createElement('DIV'); + // contents box + dom.content = document.createElement('div'); dom.content.className = 'content'; dom.box.appendChild(dom.content); - // line to axis - dom.line = document.createElement('DIV'); - dom.line.className = 'line'; - - // dot on axis - dom.dot = document.createElement('DIV'); - dom.dot.className = 'dot'; - // attach this item as attribute dom.box['timeline-item'] = this; @@ -17588,19 +17645,11 @@ return /******/ (function(modules) { // webpackBootstrap } if (!dom.box.parentNode) { var foreground = this.parent.dom.foreground; - if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); + if (!foreground) { + throw new Error('Cannot redraw item: parent has no foreground container element'); + } foreground.appendChild(dom.box); } - if (!dom.line.parentNode) { - var background = this.parent.dom.background; - if (!background) throw new Error('Cannot redraw item: parent has no background container element'); - background.appendChild(dom.line); - } - if (!dom.dot.parentNode) { - var axis = this.parent.dom.axis; - if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); - axis.appendChild(dom.dot); - } this.displayed = true; // Update DOM when item is marked dirty. An item is marked dirty when: @@ -17614,30 +17663,30 @@ return /******/ (function(modules) { // webpackBootstrap this._updateStyle(this.dom.box); // update class - var className = (this.data.className? ' ' + this.data.className : '') + + var className = (this.data.className ? (' ' + this.data.className) : '') + (this.selected ? ' selected' : ''); - dom.box.className = 'item box' + className; - dom.line.className = 'item line' + className; - dom.dot.className = 'item dot' + className; + dom.box.className = this.baseClassName + className; + + // determine from css whether this box has overflow + this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; // recalculate size - this.props.dot.height = dom.dot.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; - this.props.line.width = dom.line.offsetWidth; - this.width = dom.box.offsetWidth; - this.height = dom.box.offsetHeight; + this.props.content.width = this.dom.content.offsetWidth; + this.height = this.dom.box.offsetHeight; this.dirty = false; } this._repaintDeleteButton(dom.box); + this._repaintDragLeft(); + this._repaintDragRight(); }; /** - * Show the item in the DOM (when not already displayed). The items DOM will + * Show the item in the DOM (when not already visible). The items DOM will * be created when needed. */ - BoxItem.prototype.show = function() { + RangeItem.prototype.show = function() { if (!this.displayed) { this.redraw(); } @@ -17645,14 +17694,15 @@ return /******/ (function(modules) { // webpackBootstrap /** * Hide the item from the DOM (when visible) + * @return {Boolean} changed */ - BoxItem.prototype.hide = function() { + RangeItem.prototype.hide = function() { if (this.displayed) { - var dom = this.dom; + var box = this.dom.box; - if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); - if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); - if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); + if (box.parentNode) { + box.parentNode.removeChild(box); + } this.top = null; this.left = null; @@ -17665,66 +17715,150 @@ return /******/ (function(modules) { // webpackBootstrap * Reposition the item horizontally * @Override */ - BoxItem.prototype.repositionX = function() { + RangeItem.prototype.repositionX = function() { + var parentWidth = this.parent.width; var start = this.conversion.toScreen(this.data.start); - var align = this.options.align; - var left; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; + var end = this.conversion.toScreen(this.data.end); + var contentLeft; + var contentWidth; - // calculate left position of the box - if (align == 'right') { - this.left = start - this.width; + // limit the width of the this, as browsers cannot draw very wide divs + if (start < -parentWidth) { + start = -parentWidth; } - else if (align == 'left') { + if (end > 2 * parentWidth) { + end = 2 * parentWidth; + } + var boxWidth = Math.max(end - start, 1); + + if (this.overflow) { this.left = start; + this.width = boxWidth + this.props.content.width; + contentWidth = this.props.content.width; + + // Note: The calculation of width is an optimistic calculation, giving + // a width which will not change when moving the Timeline + // So no re-stacking needed, which is nicer for the eye; } else { - // default or 'center' - this.left = start - this.width / 2; + this.left = start; + this.width = boxWidth; + contentWidth = Math.min(end - start, this.props.content.width); } - // reposition box - box.style.left = this.left + 'px'; + this.dom.box.style.left = this.left + 'px'; + this.dom.box.style.width = boxWidth + 'px'; - // reposition line - line.style.left = (start - this.props.line.width / 2) + 'px'; + switch (this.options.align) { + case 'left': + this.dom.content.style.left = '0'; + break; - // reposition dot - dot.style.left = (start - this.props.dot.width / 2) + 'px'; + case 'right': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; + break; + + case 'center': + this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; + break; + + default: // 'auto' + if (this.overflow) { + // when range exceeds left of the window, position the contents at the left of the visible area + contentLeft = Math.max(-start, 0); + } + else { + // when range exceeds left of the window, position the contents at the left of the visible area + if (start < 0) { + contentLeft = Math.min(-start, + (end - start - this.props.content.width - 2 * this.options.padding)); + // TODO: remove the need for options.padding. it's terrible. + } + else { + contentLeft = 0; + } + } + this.dom.content.style.left = contentLeft + 'px'; + } }; /** * Reposition the item vertically * @Override */ - BoxItem.prototype.repositionY = function() { - var orientation = this.options.orientation; - var box = this.dom.box; - var line = this.dom.line; - var dot = this.dom.dot; + RangeItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + box = this.dom.box; if (orientation == 'top') { - box.style.top = (this.top || 0) + 'px'; - - line.style.top = '0'; - line.style.height = (this.parent.top + this.top + 1) + 'px'; - line.style.bottom = ''; + box.style.top = this.top + 'px'; } - else { // orientation 'bottom' - var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty - var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; + else { + box.style.top = (this.parent.height - this.top - this.height) + 'px'; + } + }; - box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; - line.style.top = (itemSetHeight - lineHeight) + 'px'; - line.style.bottom = '0'; + /** + * Repaint a drag area on the left side of the range when the range is selected + * @protected + */ + RangeItem.prototype._repaintDragLeft = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { + // create and show drag area + var dragLeft = document.createElement('div'); + dragLeft.className = 'drag-left'; + dragLeft.dragLeftItem = this; + + // TODO: this should be redundant? + Hammer(dragLeft, { + preventDefault: true + }).on('drag', function () { + //console.log('drag left') + }); + + this.dom.box.appendChild(dragLeft); + this.dom.dragLeft = dragLeft; + } + else if (!this.selected && this.dom.dragLeft) { + // delete drag area + if (this.dom.dragLeft.parentNode) { + this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); + } + this.dom.dragLeft = null; } + }; - dot.style.top = (-this.props.dot.height / 2) + 'px'; + /** + * Repaint a drag area on the right side of the range when the range is selected + * @protected + */ + RangeItem.prototype._repaintDragRight = function () { + if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { + // create and show drag area + var dragRight = document.createElement('div'); + dragRight.className = 'drag-right'; + dragRight.dragRightItem = this; + + // TODO: this should be redundant? + Hammer(dragRight, { + preventDefault: true + }).on('drag', function () { + //console.log('drag right') + }); + + this.dom.box.appendChild(dragRight); + this.dom.dragRight = dragRight; + } + else if (!this.selected && this.dom.dragRight) { + // delete drag area + if (this.dom.dragRight.parentNode) { + this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); + } + this.dom.dragRight = null; + } }; - module.exports = BoxItem; + module.exports = RangeItem; /***/ }, @@ -17994,12 +18128,76 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, /* 36 */ +/***/ function(module, exports, __webpack_require__) { + + var util = __webpack_require__(1); + var Group = __webpack_require__(32); + + /** + * @constructor BackgroundGroup + * @param {Number | String} groupId + * @param {Object} data + * @param {ItemSet} itemSet + */ + function BackgroundGroup (groupId, data, itemSet) { + Group.call(this, groupId, data, itemSet); + + this.width = 0; + this.height = 0; + this.top = 0; + this.left = 0; + } + + BackgroundGroup.prototype = Object.create(Group.prototype); + + /** + * Repaint this group + * @param {{start: number, end: number}} range + * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin + * @param {boolean} [restack=false] Force restacking of all items + * @return {boolean} Returns true if the group is resized + */ + BackgroundGroup.prototype.redraw = function(range, margin, restack) { + var resized = false; + + this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range); + + // calculate actual size + this.width = this.dom.background.offsetWidth; + + // apply new height (just always zero for BackgroundGroup + this.dom.background.style.height = '0'; + + // update vertical position of items after they are re-stacked and the height of the group is calculated + for (var i = 0, ii = this.visibleItems.length; i < ii; i++) { + var item = this.visibleItems[i]; + item.repositionY(margin); + } + + return resized; + }; + + /** + * Show this group: attach to the DOM + */ + BackgroundGroup.prototype.show = function() { + if (!this.dom.background.parentNode) { + this.itemSet.dom.background.appendChild(this.dom.background); + } + }; + + module.exports = BackgroundGroup; + + +/***/ }, +/* 37 */ /***/ function(module, exports, __webpack_require__) { var Item = __webpack_require__(35); + var util = __webpack_require__(1); /** - * @constructor PointItem + * @constructor BoxItem * @extends Item * @param {Object} data Object containing parameters start * content, className. @@ -18008,16 +18206,15 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Object} [options] Configuration options * // TODO: describe available options */ - function PointItem (data, conversion, options) { + function BoxItem (data, conversion, options) { this.props = { dot: { - top: 0, width: 0, height: 0 }, - content: { - height: 0, - marginLeft: 0 + line: { + width: 0, + height: 0 } }; @@ -18031,14 +18228,14 @@ return /******/ (function(modules) { // webpackBootstrap Item.call(this, data, conversion, options); } - PointItem.prototype = new Item (null, null, null); + BoxItem.prototype = new Item (null, null, null); /** * Check whether this item is visible inside given range * @returns {{start: Number, end: Number}} range with a timestamp for start and end * @returns {boolean} True if visible */ - PointItem.prototype.isVisible = function(range) { + BoxItem.prototype.isVisible = function(range) { // determine visibility // TODO: account for the real width of the item. Right now we just add 1/4 to the window var interval = (range.end - range.start) / 4; @@ -18048,28 +18245,31 @@ return /******/ (function(modules) { // webpackBootstrap /** * Repaint the item */ - PointItem.prototype.redraw = function() { + BoxItem.prototype.redraw = function() { var dom = this.dom; if (!dom) { // create DOM this.dom = {}; dom = this.dom; - // background box - dom.point = document.createElement('div'); - // className is updated in redraw() + // create main box + dom.box = document.createElement('DIV'); - // contents box, right from the dot - dom.content = document.createElement('div'); + // contents box (inside the background box). used for making margins + dom.content = document.createElement('DIV'); dom.content.className = 'content'; - dom.point.appendChild(dom.content); + dom.box.appendChild(dom.content); - // dot at start - dom.dot = document.createElement('div'); - dom.point.appendChild(dom.dot); + // line to axis + dom.line = document.createElement('DIV'); + dom.line.className = 'line'; + + // dot on axis + dom.dot = document.createElement('DIV'); + dom.dot.className = 'dot'; // attach this item as attribute - dom.point['timeline-item'] = this; + dom.box['timeline-item'] = this; this.dirty = true; } @@ -18078,56 +18278,58 @@ return /******/ (function(modules) { // webpackBootstrap if (!this.parent) { throw new Error('Cannot redraw item: no parent attached'); } - if (!dom.point.parentNode) { + if (!dom.box.parentNode) { var foreground = this.parent.dom.foreground; - if (!foreground) { - throw new Error('Cannot redraw item: parent has no foreground container element'); - } - foreground.appendChild(dom.point); + if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element'); + foreground.appendChild(dom.box); } - this.displayed = true; - - // Update DOM when item is marked dirty. An item is marked dirty when: - // - the item is not yet rendered - // - the item's data is changed - // - the item is selected/deselected + if (!dom.line.parentNode) { + var background = this.parent.dom.background; + if (!background) throw new Error('Cannot redraw item: parent has no background container element'); + background.appendChild(dom.line); + } + if (!dom.dot.parentNode) { + var axis = this.parent.dom.axis; + if (!background) throw new Error('Cannot redraw item: parent has no axis container element'); + axis.appendChild(dom.dot); + } + this.displayed = true; + + // Update DOM when item is marked dirty. An item is marked dirty when: + // - the item is not yet rendered + // - the item's data is changed + // - the item is selected/deselected if (this.dirty) { this._updateContents(this.dom.content); - this._updateTitle(this.dom.point); - this._updateDataAttributes(this.dom.point); - this._updateStyle(this.dom.point); + this._updateTitle(this.dom.box); + this._updateDataAttributes(this.dom.box); + this._updateStyle(this.dom.box); // update class var className = (this.data.className? ' ' + this.data.className : '') + (this.selected ? ' selected' : ''); - dom.point.className = 'item point' + className; + dom.box.className = 'item box' + className; + dom.line.className = 'item line' + className; dom.dot.className = 'item dot' + className; // recalculate size - this.width = dom.point.offsetWidth; - this.height = dom.point.offsetHeight; - this.props.dot.width = dom.dot.offsetWidth; this.props.dot.height = dom.dot.offsetHeight; - this.props.content.height = dom.content.offsetHeight; - - // resize contents - dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; - //dom.content.style.marginRight = ... + 'px'; // TODO: margin right - - dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; - dom.dot.style.left = (this.props.dot.width / 2) + 'px'; + this.props.dot.width = dom.dot.offsetWidth; + this.props.line.width = dom.line.offsetWidth; + this.width = dom.box.offsetWidth; + this.height = dom.box.offsetHeight; this.dirty = false; } - this._repaintDeleteButton(dom.point); + this._repaintDeleteButton(dom.box); }; /** - * Show the item in the DOM (when not already visible). The items DOM will + * Show the item in the DOM (when not already displayed). The items DOM will * be created when needed. */ - PointItem.prototype.show = function() { + BoxItem.prototype.show = function() { if (!this.displayed) { this.redraw(); } @@ -18136,11 +18338,13 @@ return /******/ (function(modules) { // webpackBootstrap /** * Hide the item from the DOM (when visible) */ - PointItem.prototype.hide = function() { + BoxItem.prototype.hide = function() { if (this.displayed) { - if (this.dom.point.parentNode) { - this.dom.point.parentNode.removeChild(this.dom.point); - } + var dom = this.dom; + + if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box); + if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line); + if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot); this.top = null; this.left = null; @@ -18153,107 +18357,146 @@ return /******/ (function(modules) { // webpackBootstrap * Reposition the item horizontally * @Override */ - PointItem.prototype.repositionX = function() { + BoxItem.prototype.repositionX = function() { var start = this.conversion.toScreen(this.data.start); + var align = this.options.align; + var left; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; - this.left = start - this.props.dot.width; + // calculate left position of the box + if (align == 'right') { + this.left = start - this.width; + } + else if (align == 'left') { + this.left = start; + } + else { + // default or 'center' + this.left = start - this.width / 2; + } - // reposition point - this.dom.point.style.left = this.left + 'px'; + // reposition box + box.style.left = this.left + 'px'; + + // reposition line + line.style.left = (start - this.props.line.width / 2) + 'px'; + + // reposition dot + dot.style.left = (start - this.props.dot.width / 2) + 'px'; }; /** * Reposition the item vertically * @Override */ - PointItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - point = this.dom.point; + BoxItem.prototype.repositionY = function() { + var orientation = this.options.orientation; + var box = this.dom.box; + var line = this.dom.line; + var dot = this.dom.dot; if (orientation == 'top') { - point.style.top = this.top + 'px'; + box.style.top = (this.top || 0) + 'px'; + + line.style.top = '0'; + line.style.height = (this.parent.top + this.top + 1) + 'px'; + line.style.bottom = ''; } - else { - point.style.top = (this.parent.height - this.top - this.height) + 'px'; + else { // orientation 'bottom' + var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty + var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top; + + box.style.top = (this.parent.height - this.top - this.height || 0) + 'px'; + line.style.top = (itemSetHeight - lineHeight) + 'px'; + line.style.bottom = '0'; } + + dot.style.top = (-this.props.dot.height / 2) + 'px'; }; - module.exports = PointItem; + module.exports = BoxItem; /***/ }, -/* 37 */ +/* 38 */ /***/ function(module, exports, __webpack_require__) { - var Hammer = __webpack_require__(19); var Item = __webpack_require__(35); /** - * @constructor RangeItem + * @constructor PointItem * @extends Item - * @param {Object} data Object containing parameters start, end + * @param {Object} data Object containing parameters start * content, className. * @param {{toScreen: function, toTime: function}} conversion * Conversion functions from time to screen and vice versa * @param {Object} [options] Configuration options - * // TODO: describe options + * // TODO: describe available options */ - function RangeItem (data, conversion, options) { + function PointItem (data, conversion, options) { this.props = { + dot: { + top: 0, + width: 0, + height: 0 + }, content: { - width: 0 + height: 0, + marginLeft: 0 } }; - this.overflow = false; // if contents can overflow (css styling), this flag is set to true // validate data if (data) { if (data.start == undefined) { - throw new Error('Property "start" missing in item ' + data.id); - } - if (data.end == undefined) { - throw new Error('Property "end" missing in item ' + data.id); + throw new Error('Property "start" missing in item ' + data); } } Item.call(this, data, conversion, options); } - RangeItem.prototype = new Item (null, null, null); - - RangeItem.prototype.baseClassName = 'item range'; + PointItem.prototype = new Item (null, null, null); /** * Check whether this item is visible inside given range * @returns {{start: Number, end: Number}} range with a timestamp for start and end * @returns {boolean} True if visible */ - RangeItem.prototype.isVisible = function(range) { + PointItem.prototype.isVisible = function(range) { // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); + // TODO: account for the real width of the item. Right now we just add 1/4 to the window + var interval = (range.end - range.start) / 4; + return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); }; /** * Repaint the item */ - RangeItem.prototype.redraw = function() { + PointItem.prototype.redraw = function() { var dom = this.dom; if (!dom) { // create DOM this.dom = {}; dom = this.dom; - // background box - dom.box = document.createElement('div'); + // background box + dom.point = document.createElement('div'); // className is updated in redraw() - // contents box + // contents box, right from the dot dom.content = document.createElement('div'); dom.content.className = 'content'; - dom.box.appendChild(dom.content); + dom.point.appendChild(dom.content); + + // dot at start + dom.dot = document.createElement('div'); + dom.point.appendChild(dom.dot); // attach this item as attribute - dom.box['timeline-item'] = this; + dom.point['timeline-item'] = this; this.dirty = true; } @@ -18262,12 +18505,12 @@ return /******/ (function(modules) { // webpackBootstrap if (!this.parent) { throw new Error('Cannot redraw item: no parent attached'); } - if (!dom.box.parentNode) { + if (!dom.point.parentNode) { var foreground = this.parent.dom.foreground; if (!foreground) { throw new Error('Cannot redraw item: parent has no foreground container element'); } - foreground.appendChild(dom.box); + foreground.appendChild(dom.point); } this.displayed = true; @@ -18277,217 +18520,102 @@ return /******/ (function(modules) { // webpackBootstrap // - the item is selected/deselected if (this.dirty) { this._updateContents(this.dom.content); - this._updateTitle(this.dom.box); - this._updateDataAttributes(this.dom.box); - this._updateStyle(this.dom.box); + this._updateTitle(this.dom.point); + this._updateDataAttributes(this.dom.point); + this._updateStyle(this.dom.point); // update class - var className = (this.data.className ? (' ' + this.data.className) : '') + + var className = (this.data.className? ' ' + this.data.className : '') + (this.selected ? ' selected' : ''); - dom.box.className = this.baseClassName + className; - - // determine from css whether this box has overflow - this.overflow = window.getComputedStyle(dom.content).overflow !== 'hidden'; + dom.point.className = 'item point' + className; + dom.dot.className = 'item dot' + className; // recalculate size - this.props.content.width = this.dom.content.offsetWidth; - this.height = this.dom.box.offsetHeight; - - this.dirty = false; - } - - this._repaintDeleteButton(dom.box); - this._repaintDragLeft(); - this._repaintDragRight(); - }; - - /** - * Show the item in the DOM (when not already visible). The items DOM will - * be created when needed. - */ - RangeItem.prototype.show = function() { - if (!this.displayed) { - this.redraw(); - } - }; - - /** - * Hide the item from the DOM (when visible) - * @return {Boolean} changed - */ - RangeItem.prototype.hide = function() { - if (this.displayed) { - var box = this.dom.box; - - if (box.parentNode) { - box.parentNode.removeChild(box); - } - - this.top = null; - this.left = null; - - this.displayed = false; - } - }; - - /** - * Reposition the item horizontally - * @Override - */ - RangeItem.prototype.repositionX = function() { - var parentWidth = this.parent.width; - var start = this.conversion.toScreen(this.data.start); - var end = this.conversion.toScreen(this.data.end); - var contentLeft; - var contentWidth; - - // limit the width of the this, as browsers cannot draw very wide divs - if (start < -parentWidth) { - start = -parentWidth; - } - if (end > 2 * parentWidth) { - end = 2 * parentWidth; - } - var boxWidth = Math.max(end - start, 1); - - if (this.overflow) { - this.left = start; - this.width = boxWidth + this.props.content.width; - contentWidth = this.props.content.width; - - // Note: The calculation of width is an optimistic calculation, giving - // 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; - this.width = boxWidth; - contentWidth = Math.min(end - start, this.props.content.width); - } - - 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'; - break; - - case 'right': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding), 0) + 'px'; - break; - - case 'center': - this.dom.content.style.left = Math.max((boxWidth - contentWidth - 2 * this.options.padding) / 2, 0) + 'px'; - break; - - default: // 'auto' - if (this.overflow) { - // when range exceeds left of the window, position the contents at the left of the visible area - contentLeft = Math.max(-start, 0); - } - else { - // when range exceeds left of the window, position the contents at the left of the visible area - if (start < 0) { - contentLeft = Math.min(-start, - (end - start - this.props.content.width - 2 * this.options.padding)); - // TODO: remove the need for options.padding. it's terrible. - } - else { - contentLeft = 0; - } - } - this.dom.content.style.left = contentLeft + 'px'; + this.width = dom.point.offsetWidth; + this.height = dom.point.offsetHeight; + this.props.dot.width = dom.dot.offsetWidth; + this.props.dot.height = dom.dot.offsetHeight; + this.props.content.height = dom.content.offsetHeight; + + // resize contents + dom.content.style.marginLeft = 2 * this.props.dot.width + 'px'; + //dom.content.style.marginRight = ... + 'px'; // TODO: margin right + + dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px'; + dom.dot.style.left = (this.props.dot.width / 2) + 'px'; + + this.dirty = false; } + + this._repaintDeleteButton(dom.point); }; /** - * Reposition the item vertically - * @Override + * Show the item in the DOM (when not already visible). The items DOM will + * be created when needed. */ - RangeItem.prototype.repositionY = function() { - var orientation = this.options.orientation, - box = this.dom.box; - - if (orientation == 'top') { - box.style.top = this.top + 'px'; - } - else { - box.style.top = (this.parent.height - this.top - this.height) + 'px'; + PointItem.prototype.show = function() { + if (!this.displayed) { + this.redraw(); } }; /** - * Repaint a drag area on the left side of the range when the range is selected - * @protected + * Hide the item from the DOM (when visible) */ - RangeItem.prototype._repaintDragLeft = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) { - // create and show drag area - var dragLeft = document.createElement('div'); - dragLeft.className = 'drag-left'; - dragLeft.dragLeftItem = this; + PointItem.prototype.hide = function() { + if (this.displayed) { + if (this.dom.point.parentNode) { + this.dom.point.parentNode.removeChild(this.dom.point); + } - // TODO: this should be redundant? - Hammer(dragLeft, { - preventDefault: true - }).on('drag', function () { - //console.log('drag left') - }); + this.top = null; + this.left = null; - this.dom.box.appendChild(dragLeft); - this.dom.dragLeft = dragLeft; - } - else if (!this.selected && this.dom.dragLeft) { - // delete drag area - if (this.dom.dragLeft.parentNode) { - this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft); - } - this.dom.dragLeft = null; + this.displayed = false; } }; /** - * Repaint a drag area on the right side of the range when the range is selected - * @protected + * Reposition the item horizontally + * @Override */ - RangeItem.prototype._repaintDragRight = function () { - if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) { - // create and show drag area - var dragRight = document.createElement('div'); - dragRight.className = 'drag-right'; - dragRight.dragRightItem = this; + PointItem.prototype.repositionX = function() { + var start = this.conversion.toScreen(this.data.start); - // TODO: this should be redundant? - Hammer(dragRight, { - preventDefault: true - }).on('drag', function () { - //console.log('drag right') - }); + this.left = start - this.props.dot.width; - this.dom.box.appendChild(dragRight); - this.dom.dragRight = dragRight; + // reposition point + this.dom.point.style.left = this.left + 'px'; + }; + + /** + * Reposition the item vertically + * @Override + */ + PointItem.prototype.repositionY = function() { + var orientation = this.options.orientation, + point = this.dom.point; + + if (orientation == 'top') { + point.style.top = this.top + 'px'; } - else if (!this.selected && this.dom.dragRight) { - // delete drag area - if (this.dom.dragRight.parentNode) { - this.dom.dragRight.parentNode.removeChild(this.dom.dragRight); - } - this.dom.dragRight = null; + else { + point.style.top = (this.parent.height - this.top - this.height) + 'px'; } }; - module.exports = RangeItem; + module.exports = PointItem; /***/ }, -/* 38 */ +/* 39 */ /***/ function(module, exports, __webpack_require__) { var Hammer = __webpack_require__(19); var Item = __webpack_require__(35); - var BackgroundGroup = __webpack_require__(33); - var RangeItem = __webpack_require__(37); + var BackgroundGroup = __webpack_require__(36); + var RangeItem = __webpack_require__(34); /** * @constructor BackgroundItem @@ -18694,10 +18822,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 39 */ +/* 40 */ /***/ function(module, exports, __webpack_require__) { - var keycharm = __webpack_require__(40); + var keycharm = __webpack_require__(41); var Emitter = __webpack_require__(11); var Hammer = __webpack_require__(19); var util = __webpack_require__(1); @@ -18851,7 +18979,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 40 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** @@ -19044,7 +19172,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 41 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(11); @@ -19057,7 +19185,7 @@ return /******/ (function(modules) { // webpackBootstrap var TimeAxis = __webpack_require__(26); var CurrentTime = __webpack_require__(28); var CustomTime = __webpack_require__(30); - var LineGraph = __webpack_require__(42); + var LineGraph = __webpack_require__(43); /** * Create a timeline visualization @@ -19294,7 +19422,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 42 */ +/* 43 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -19302,10 +19430,10 @@ return /******/ (function(modules) { // webpackBootstrap var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); var Component = __webpack_require__(23); - var DataAxis = __webpack_require__(43); - var GraphGroup = __webpack_require__(45); - var Legend = __webpack_require__(49); - var BarGraphFunctions = __webpack_require__(48); + var DataAxis = __webpack_require__(44); + var GraphGroup = __webpack_require__(46); + var Legend = __webpack_require__(50); + var BarGraphFunctions = __webpack_require__(49); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -20257,13 +20385,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 43 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); var Component = __webpack_require__(23); - var DataStep = __webpack_require__(44); + var DataStep = __webpack_require__(45); /** * A horizontal time axis @@ -20858,7 +20986,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 44 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { /** @@ -21126,14 +21254,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 45 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); - var Line = __webpack_require__(46); - var Bar = __webpack_require__(48); - var Points = __webpack_require__(47); + var Line = __webpack_require__(47); + var Bar = __webpack_require__(49); + var Points = __webpack_require__(48); /** * /** @@ -21331,14 +21459,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 46 */ +/* 47 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(47); + var Points = __webpack_require__(48); function Line(groupId, options) { this.groupId = groupId; @@ -21555,7 +21683,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ +/* 48 */ /***/ function(module, exports, __webpack_require__) { /** @@ -21603,14 +21731,14 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Points; /***/ }, -/* 48 */ +/* 49 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(47); + var Points = __webpack_require__(48); function Bargraph(groupId, options) { this.groupId = groupId; @@ -21837,7 +21965,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Bargraph; /***/ }, -/* 49 */ +/* 50 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -22046,141 +22174,13 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Legend; -/***/ }, -/* 50 */ -/***/ function(module, exports, __webpack_require__) { - - // Utility functions for ordering and stacking of items - var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors - - /** - * Order items by their start data - * @param {Item[]} items - */ - exports.orderByStart = function(items) { - items.sort(function (a, b) { - return a.data.start - b.data.start; - }); - }; - - /** - * Order items by their end date. If they have no end date, their start date - * is used. - * @param {Item[]} items - */ - exports.orderByEnd = function(items) { - items.sort(function (a, b) { - var aTime = ('end' in a.data) ? a.data.end : a.data.start, - bTime = ('end' in b.data) ? b.data.end : b.data.start; - - return aTime - bTime; - }); - }; - - /** - * Adjust vertical positions of the items such that they don't overlap each - * other. - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - * @param {boolean} [force=false] - * If true, all items will be repositioned. If false (default), only - * items having a top===null will be re-stacked - */ - 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++) { - items[i].top = null; - } - } - - // calculate new, non-overlapping positions - for (i = 0, iMax = items.length; i < iMax; i++) { - var item = items[i]; - if (item.stack && item.top === null) { - // initialize top position - item.top = margin.axis; - - do { - // TODO: optimize checking for overlap. when there is a gap without items, - // you only need to check for items from the next item on, not from zero - 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)) { - collidingItem = other; - break; - } - } - - if (collidingItem != null) { - // There is a collision. Reposition the items above the colliding element - item.top = collidingItem.top + collidingItem.height + margin.item.vertical; - } - } while (collidingItem); - } - } - }; - - - /** - * Adjust vertical positions of the items without stacking them - * @param {Item[]} items - * All visible items - * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin - * Margins between items and between items and the axis. - */ - exports.nostack = function(items, margin, subgroups) { - var i, iMax, newTop; - - // reset top position of all items - for (i = 0, iMax = items.length; i < iMax; i++) { - if (items[i].data.subgroup !== undefined) { - newTop = margin.axis; - for (var subgroup in subgroups) { - if (subgroups.hasOwnProperty(subgroup)) { - if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) { - newTop += subgroups[subgroup].height + margin.item.vertical; - } - } - } - items[i].top = newTop; - } - else { - items[i].top = margin.axis; - } - } - }; - - /** - * Test if the two provided items collide - * The items must have parameters left, width, top, and height. - * @param {Item} a The first item - * @param {Item} b The second item - * @param {{horizontal: number, vertical: number}} margin - * An object containing a horizontal and vertical - * 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); - }; - - /***/ }, /* 51 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(11); var Hammer = __webpack_require__(19); - var keycharm = __webpack_require__(40); + var keycharm = __webpack_require__(41); var util = __webpack_require__(1); var hammerUtil = __webpack_require__(22); var DataSet = __webpack_require__(7); @@ -22193,7 +22193,7 @@ return /******/ (function(modules) { // webpackBootstrap var Edge = __webpack_require__(57); var Popup = __webpack_require__(58); var MixinLoader = __webpack_require__(59); - var Activator = __webpack_require__(39); + var Activator = __webpack_require__(40); var locales = __webpack_require__(70); // Load custom shapes into CanvasRenderingContext2D @@ -32716,9 +32716,8 @@ return /******/ (function(modules) { // webpackBootstrap this._navigationReleaseOverload = function () {}; // clean up previous navigation items - var wrapper = document.getElementById('network-navigation_wrapper'); - if (wrapper && wrapper.parentNode) { - wrapper.parentNode.removeChild(wrapper); + if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { + this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); } }; @@ -32738,7 +32737,6 @@ return /******/ (function(modules) { // webpackBootstrap var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; this.navigationDivs['wrapper'] = document.createElement('div'); - this.navigationDivs['wrapper'].id = 'network-navigation_wrapper'; this.frame.appendChild(this.navigationDivs['wrapper']); for (var i = 0; i < navigationDivs.length; i++) { diff --git a/lib/network/mixins/NavigationMixin.js b/lib/network/mixins/NavigationMixin.js index 10f9fe4c..4736f2a0 100644 --- a/lib/network/mixins/NavigationMixin.js +++ b/lib/network/mixins/NavigationMixin.js @@ -13,9 +13,8 @@ exports._cleanNavigation = function() { this._navigationReleaseOverload = function () {}; // clean up previous navigation items - var wrapper = document.getElementById('network-navigation_wrapper'); - if (wrapper && wrapper.parentNode) { - wrapper.parentNode.removeChild(wrapper); + if (this.navigationDivs && this.navigationDivs['wrapper'] && this.navigationDivs['wrapper'].parentNode) { + this.navigationDivs['wrapper'].parentNode.removeChild(this.navigationDivs['wrapper']); } }; @@ -35,7 +34,6 @@ exports._loadNavigationElements = function() { var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','_zoomExtent']; this.navigationDivs['wrapper'] = document.createElement('div'); - this.navigationDivs['wrapper'].id = 'network-navigation_wrapper'; this.frame.appendChild(this.navigationDivs['wrapper']); for (var i = 0; i < navigationDivs.length; i++) { diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 42476d32..d9ddbff2 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -405,7 +405,7 @@ Group.prototype.order = function() { */ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, range) { var visibleItems = []; - var visibleItemsLookup = {}; + var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems var interval = (range.end - range.start) / 4; var lowerBound = range.start - interval; var upperBound = range.end + interval;