diff --git a/HISTORY.md b/HISTORY.md index e3437b9e..066ca314 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -7,12 +7,18 @@ http://visjs.org - Added points style for scatterplots and pointclouds. - Modularized the Graph2D draw styles. +- Added a finishedRedraw event. ### Network - Added pointer properties to the click and the doubleClick events containing the XY coordinates in DOM and canvas space. - Removed IDs from navigation so multiple networks can be shown on the same page. (#438) + +### Timeline + +- Added a finishedRedraw event. + ## 2014-11-07, version 3.6.4 ### General diff --git a/dist/vis.js b/dist/vis.js index 0421e121..c867002a 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -101,10 +101,10 @@ return /******/ (function(modules) { // webpackBootstrap // Timeline exports.Timeline = __webpack_require__(18); - exports.Graph2d = __webpack_require__(42); + exports.Graph2d = __webpack_require__(40); exports.timeline = { DateUtil: __webpack_require__(24), - DataStep: __webpack_require__(45), + DataStep: __webpack_require__(43), Range: __webpack_require__(21), stack: __webpack_require__(33), TimeStep: __webpack_require__(27), @@ -121,27 +121,27 @@ return /******/ (function(modules) { // webpackBootstrap Component: __webpack_require__(23), CurrentTime: __webpack_require__(28), CustomTime: __webpack_require__(30), - DataAxis: __webpack_require__(44), - GraphGroup: __webpack_require__(46), + DataAxis: __webpack_require__(42), + GraphGroup: __webpack_require__(44), Group: __webpack_require__(32), BackgroundGroup: __webpack_require__(36), ItemSet: __webpack_require__(31), - Legend: __webpack_require__(50), - LineGraph: __webpack_require__(43), + Legend: __webpack_require__(48), + LineGraph: __webpack_require__(41), TimeAxis: __webpack_require__(26) } }; // Network - exports.Network = __webpack_require__(51); + exports.Network = __webpack_require__(49); exports.network = { - Edge: __webpack_require__(57), - Groups: __webpack_require__(54), - Images: __webpack_require__(55), - Node: __webpack_require__(56), - Popup: __webpack_require__(58), - dotparser: __webpack_require__(52), - gephiParser: __webpack_require__(53) + Edge: __webpack_require__(56), + Groups: __webpack_require__(53), + Images: __webpack_require__(54), + Node: __webpack_require__(55), + Popup: __webpack_require__(57), + dotparser: __webpack_require__(51), + gephiParser: __webpack_require__(52) }; // Deprecated since v3.0.0 @@ -13232,7 +13232,7 @@ return /******/ (function(modules) { // webpackBootstrap var CurrentTime = __webpack_require__(28); var CustomTime = __webpack_require__(30); var ItemSet = __webpack_require__(31); - var Activator = __webpack_require__(40); + var Activator = __webpack_require__(69); var DateUtil = __webpack_require__(24); /** @@ -13819,6 +13819,8 @@ return /******/ (function(modules) { // webpackBootstrap // keep repainting until all sizes are settled this.redraw(); } + + this.emit("finishedRedraw"); }; // TODO: deprecated since version 1.1.0, remove some day @@ -18789,356 +18791,6 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, /* 40 */ -/***/ function(module, exports, __webpack_require__) { - - var keycharm = __webpack_require__(41); - var Emitter = __webpack_require__(11); - var Hammer = __webpack_require__(19); - var util = __webpack_require__(1); - - /** - * Turn an element into an clickToUse element. - * When not active, the element has a transparent overlay. When the overlay is - * clicked, the mode is changed to active. - * When active, the element is displayed with a blue border around it, and - * the interactive contents of the element can be used. When clicked outside - * the element, the elements mode is changed to inactive. - * @param {Element} container - * @constructor - */ - function Activator(container) { - this.active = false; - - this.dom = { - container: container - }; - - this.dom.overlay = document.createElement('div'); - this.dom.overlay.className = 'overlay'; - - this.dom.container.appendChild(this.dom.overlay); - - this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); - this.hammer.on('tap', this._onTapOverlay.bind(this)); - - // block all touch events (except tap) - var me = this; - var events = [ - 'touch', 'pinch', - 'doubletap', 'hold', - 'dragstart', 'drag', 'dragend', - 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox - ]; - events.forEach(function (event) { - me.hammer.on(event, function (event) { - event.stopPropagation(); - }); - }); - - // attach a tap event to the window, in order to deactivate when clicking outside the timeline - this.windowHammer = Hammer(window, {prevent_default: false}); - this.windowHammer.on('tap', function (event) { - // deactivate when clicked outside the container - if (!_hasParent(event.target, container)) { - me.deactivate(); - } - }); - - if (this.keycharm !== undefined) { - this.keycharm.destroy(); - } - this.keycharm = keycharm(); - - // keycharm listener only bounded when active) - this.escListener = this.deactivate.bind(this); - } - - // turn into an event emitter - Emitter(Activator.prototype); - - // The currently active activator - Activator.current = null; - - /** - * Destroy the activator. Cleans up all created DOM and event listeners - */ - Activator.prototype.destroy = function () { - this.deactivate(); - - // remove dom - this.dom.overlay.parentNode.removeChild(this.dom.overlay); - - // cleanup hammer instances - this.hammer = null; - this.windowHammer = null; - // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) - }; - - /** - * Activate the element - * Overlay is hidden, element is decorated with a blue shadow border - */ - Activator.prototype.activate = function () { - // we allow only one active activator at a time - if (Activator.current) { - Activator.current.deactivate(); - } - Activator.current = this; - - this.active = true; - this.dom.overlay.style.display = 'none'; - util.addClassName(this.dom.container, 'vis-active'); - - this.emit('change'); - this.emit('activate'); - - // ugly hack: bind ESC after emitting the events, as the Network rebinds all - // keyboard events on a 'change' event - this.keycharm.bind('esc', this.escListener); - }; - - /** - * Deactivate the element - * Overlay is displayed on top of the element - */ - Activator.prototype.deactivate = function () { - this.active = false; - this.dom.overlay.style.display = ''; - util.removeClassName(this.dom.container, 'vis-active'); - this.keycharm.unbind('esc', this.escListener); - - this.emit('change'); - this.emit('deactivate'); - }; - - /** - * Handle a tap event: activate the container - * @param event - * @private - */ - Activator.prototype._onTapOverlay = function (event) { - // activate the container - this.activate(); - event.stopPropagation(); - }; - - /** - * Test whether the element has the requested parent element somewhere in - * its chain of parent nodes. - * @param {HTMLElement} element - * @param {HTMLElement} parent - * @returns {boolean} Returns true when the parent is found somewhere in the - * chain of parent nodes. - * @private - */ - function _hasParent(element, parent) { - while (element) { - if (element === parent) { - return true - } - element = element.parentNode; - } - return false; - } - - module.exports = Activator; - - -/***/ }, -/* 41 */ -/***/ function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** - * Created by Alex on 11/6/2014. - */ - - // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 - // if the module has no dependencies, the above pattern can be simplified to - (function (root, factory) { - if (true) { - // AMD. Register as an anonymous module. - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports === 'object') { - // Node. Does not work with strict CommonJS, but - // only CommonJS-like environments that support module.exports, - // like Node. - module.exports = factory(); - } else { - // Browser globals (root is window) - root.keycharm = factory(); - } - }(this, function () { - - function keycharm(options) { - var preventDefault = options && options.preventDefault || false; - - var _bound = {keydown:{}, keyup:{}}; - var _keys = {}; - var i; - - // a - z - for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} - // A - Z - for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} - // 0 - 9 - for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} - // F1 - F12 - for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} - // num0 - num9 - for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} - - // numpad misc - _keys['num*'] = {code:106, shift: false}; - _keys['num+'] = {code:107, shift: false}; - _keys['num-'] = {code:109, shift: false}; - _keys['num/'] = {code:111, shift: false}; - _keys['num.'] = {code:110, shift: false}; - // arrows - _keys['left'] = {code:37, shift: false}; - _keys['up'] = {code:38, shift: false}; - _keys['right'] = {code:39, shift: false}; - _keys['down'] = {code:40, shift: false}; - // extra keys - _keys['space'] = {code:32, shift: false}; - _keys['enter'] = {code:13, shift: false}; - _keys['shift'] = {code:16, shift: undefined}; - _keys['esc'] = {code:27, shift: false}; - _keys['backspace'] = {code:8, shift: false}; - _keys['tab'] = {code:9, shift: false}; - _keys['ctrl'] = {code:17, shift: false}; - _keys['alt'] = {code:18, shift: false}; - _keys['delete'] = {code:46, shift: false}; - _keys['pageup'] = {code:33, shift: false}; - _keys['pagedown'] = {code:34, shift: false}; - // symbols - _keys['='] = {code:187, shift: false}; - _keys['-'] = {code:189, shift: false}; - _keys[']'] = {code:221, shift: false}; - _keys['['] = {code:219, shift: false}; - - - - var down = function(event) {handleEvent(event,'keydown');}; - var up = function(event) {handleEvent(event,'keyup');}; - - // handle the actualy bound key with the event - var handleEvent = function(event,type) { - if (_bound[type][event.keyCode] !== undefined) { - var bound = _bound[type][event.keyCode]; - for (var i = 0; i < bound.length; i++) { - if (bound[i].shift === undefined) { - bound[i].fn(event); - } - else if (bound[i].shift == true && event.shiftKey == true) { - bound[i].fn(event); - } - else if (bound[i].shift == false && event.shiftKey == false) { - bound[i].fn(event); - } - } - - if (preventDefault == true) { - event.preventDefault(); - } - } - }; - - // bind a key to a callback - this.bind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); - } - if (_bound[type][_keys[key].code] === undefined) { - _bound[type][_keys[key].code] = []; - } - _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); - }; - - - // bind all keys to a call back (demo purposes) - this.bindAll = function(callback, type) { - if (type === undefined) { - type = 'keydown'; - } - for (key in _keys) { - if (_keys.hasOwnProperty(key)) { - this.bind(key,callback,type); - } - } - } - - // get the key label from an event - this.getKey = function(event) { - for (key in _keys) { - if (_keys.hasOwnProperty(key)) { - if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { - return key; - } - else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { - return key; - } - else if (event.keyCode == _keys[key].code && key == 'shift') { - return key; - } - } - } - return "unknown key, currently not supported"; - }; - - // unbind either a specific callback from a key or all of them (by leaving callback undefined) - this.unbind = function(key, callback, type) { - if (type === undefined) { - type = 'keydown'; - } - if (_keys[key] === undefined) { - throw new Error("unsupported key: " + key); - } - if (callback !== undefined) { - var newBindings = []; - var bound = _bound[type][_keys[key].code] - for (var i = 0; i < bound.length; i++) { - if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { - newBindings.push(_bound[type][_keys[key].code][i]); - } - } - _bound[type][_keys[key].code] = newBindings; - } - else { - _bound[type][_keys[key].code] = []; - } - }; - - // reset all bound variables. - this.reset = function() { - _bound = {keydown:{}, keyup:{}}; - }; - - // unbind all listeners and reset all variables. - this.destroy = function() { - _bound = {keydown:{}, keyup:{}}; - window.removeEventListener('keydown', down, true); - window.removeEventListener('keyup', up, true); - }; - - // create listeners. - window.addEventListener('keydown',down,true); - window.addEventListener('keyup',up,true); - - // return the public functions. - return this; - } - - return keycharm; - })); - - - - -/***/ }, -/* 42 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(11); @@ -19151,7 +18803,7 @@ return /******/ (function(modules) { // webpackBootstrap var TimeAxis = __webpack_require__(26); var CurrentTime = __webpack_require__(28); var CustomTime = __webpack_require__(30); - var LineGraph = __webpack_require__(43); + var LineGraph = __webpack_require__(41); /** * Create a timeline visualization @@ -19388,7 +19040,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 43 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -19396,10 +19048,10 @@ return /******/ (function(modules) { // webpackBootstrap var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); var Component = __webpack_require__(23); - var DataAxis = __webpack_require__(44); - var GraphGroup = __webpack_require__(46); - var Legend = __webpack_require__(50); - var BarGraphFunctions = __webpack_require__(49); + var DataAxis = __webpack_require__(42); + var GraphGroup = __webpack_require__(44); + var Legend = __webpack_require__(48); + var BarGraphFunctions = __webpack_require__(47); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -20351,13 +20003,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 44 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); var Component = __webpack_require__(23); - var DataStep = __webpack_require__(45); + var DataStep = __webpack_require__(43); /** * A horizontal time axis @@ -20952,7 +20604,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 45 */ +/* 43 */ /***/ function(module, exports, __webpack_require__) { /** @@ -21220,14 +20872,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 46 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); - var Line = __webpack_require__(47); - var Bar = __webpack_require__(49); - var Points = __webpack_require__(48); + var Line = __webpack_require__(45); + var Bar = __webpack_require__(47); + var Points = __webpack_require__(46); /** * /** @@ -21425,14 +21077,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(48); + var Points = __webpack_require__(46); function Line(groupId, options) { this.groupId = groupId; @@ -21649,7 +21301,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 48 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { /** @@ -21697,14 +21349,14 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Points; /***/ }, -/* 49 */ +/* 47 */ /***/ function(module, exports, __webpack_require__) { /** * Created by Alex on 11/11/2014. */ var DOMutil = __webpack_require__(6); - var Points = __webpack_require__(48); + var Points = __webpack_require__(46); function Bargraph(groupId, options) { this.groupId = groupId; @@ -21931,7 +21583,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Bargraph; /***/ }, -/* 50 */ +/* 48 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -22141,25 +21793,25 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 51 */ +/* 49 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(11); var Hammer = __webpack_require__(19); - var keycharm = __webpack_require__(41); + var keycharm = __webpack_require__(50); var util = __webpack_require__(1); var hammerUtil = __webpack_require__(22); var DataSet = __webpack_require__(7); var DataView = __webpack_require__(9); - var dotparser = __webpack_require__(52); - var gephiParser = __webpack_require__(53); - var Groups = __webpack_require__(54); - var Images = __webpack_require__(55); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); - var Popup = __webpack_require__(58); - var MixinLoader = __webpack_require__(59); - var Activator = __webpack_require__(40); + var dotparser = __webpack_require__(51); + var gephiParser = __webpack_require__(52); + var Groups = __webpack_require__(53); + var Images = __webpack_require__(54); + var Node = __webpack_require__(55); + var Edge = __webpack_require__(56); + var Popup = __webpack_require__(57); + var MixinLoader = __webpack_require__(58); + var Activator = __webpack_require__(69); var locales = __webpack_require__(70); // Load custom shapes into CanvasRenderingContext2D @@ -24694,7 +24346,200 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 52 */ +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** + * Created by Alex on 11/6/2014. + */ + + // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60 + // if the module has no dependencies, the above pattern can be simplified to + (function (root, factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.keycharm = factory(); + } + }(this, function () { + + function keycharm(options) { + var preventDefault = options && options.preventDefault || false; + + var _bound = {keydown:{}, keyup:{}}; + var _keys = {}; + var i; + + // a - z + for (i = 97; i <= 122; i++) {_keys[String.fromCharCode(i)] = {code:65 + (i - 97), shift: false};} + // A - Z + for (i = 65; i <= 90; i++) {_keys[String.fromCharCode(i)] = {code:i, shift: true};} + // 0 - 9 + for (i = 0; i <= 9; i++) {_keys['' + i] = {code:48 + i, shift: false};} + // F1 - F12 + for (i = 1; i <= 12; i++) {_keys['F' + i] = {code:111 + i, shift: false};} + // num0 - num9 + for (i = 0; i <= 9; i++) {_keys['num' + i] = {code:96 + i, shift: false};} + + // numpad misc + _keys['num*'] = {code:106, shift: false}; + _keys['num+'] = {code:107, shift: false}; + _keys['num-'] = {code:109, shift: false}; + _keys['num/'] = {code:111, shift: false}; + _keys['num.'] = {code:110, shift: false}; + // arrows + _keys['left'] = {code:37, shift: false}; + _keys['up'] = {code:38, shift: false}; + _keys['right'] = {code:39, shift: false}; + _keys['down'] = {code:40, shift: false}; + // extra keys + _keys['space'] = {code:32, shift: false}; + _keys['enter'] = {code:13, shift: false}; + _keys['shift'] = {code:16, shift: undefined}; + _keys['esc'] = {code:27, shift: false}; + _keys['backspace'] = {code:8, shift: false}; + _keys['tab'] = {code:9, shift: false}; + _keys['ctrl'] = {code:17, shift: false}; + _keys['alt'] = {code:18, shift: false}; + _keys['delete'] = {code:46, shift: false}; + _keys['pageup'] = {code:33, shift: false}; + _keys['pagedown'] = {code:34, shift: false}; + // symbols + _keys['='] = {code:187, shift: false}; + _keys['-'] = {code:189, shift: false}; + _keys[']'] = {code:221, shift: false}; + _keys['['] = {code:219, shift: false}; + + + + var down = function(event) {handleEvent(event,'keydown');}; + var up = function(event) {handleEvent(event,'keyup');}; + + // handle the actualy bound key with the event + var handleEvent = function(event,type) { + if (_bound[type][event.keyCode] !== undefined) { + var bound = _bound[type][event.keyCode]; + for (var i = 0; i < bound.length; i++) { + if (bound[i].shift === undefined) { + bound[i].fn(event); + } + else if (bound[i].shift == true && event.shiftKey == true) { + bound[i].fn(event); + } + else if (bound[i].shift == false && event.shiftKey == false) { + bound[i].fn(event); + } + } + + if (preventDefault == true) { + event.preventDefault(); + } + } + }; + + // bind a key to a callback + this.bind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (_bound[type][_keys[key].code] === undefined) { + _bound[type][_keys[key].code] = []; + } + _bound[type][_keys[key].code].push({fn:callback, shift:_keys[key].shift}); + }; + + + // bind all keys to a call back (demo purposes) + this.bindAll = function(callback, type) { + if (type === undefined) { + type = 'keydown'; + } + for (key in _keys) { + if (_keys.hasOwnProperty(key)) { + this.bind(key,callback,type); + } + } + } + + // get the key label from an event + this.getKey = function(event) { + for (key in _keys) { + if (_keys.hasOwnProperty(key)) { + if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) { + return key; + } + else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) { + return key; + } + else if (event.keyCode == _keys[key].code && key == 'shift') { + return key; + } + } + } + return "unknown key, currently not supported"; + }; + + // unbind either a specific callback from a key or all of them (by leaving callback undefined) + this.unbind = function(key, callback, type) { + if (type === undefined) { + type = 'keydown'; + } + if (_keys[key] === undefined) { + throw new Error("unsupported key: " + key); + } + if (callback !== undefined) { + var newBindings = []; + var bound = _bound[type][_keys[key].code] + for (var i = 0; i < bound.length; i++) { + if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) { + newBindings.push(_bound[type][_keys[key].code][i]); + } + } + _bound[type][_keys[key].code] = newBindings; + } + else { + _bound[type][_keys[key].code] = []; + } + }; + + // reset all bound variables. + this.reset = function() { + _bound = {keydown:{}, keyup:{}}; + }; + + // unbind all listeners and reset all variables. + this.destroy = function() { + _bound = {keydown:{}, keyup:{}}; + window.removeEventListener('keydown', down, true); + window.removeEventListener('keyup', up, true); + }; + + // create listeners. + window.addEventListener('keydown',down,true); + window.addEventListener('keyup',up,true); + + // return the public functions. + return this; + } + + return keycharm; + })); + + + + +/***/ }, +/* 51 */ /***/ function(module, exports, __webpack_require__) { /** @@ -25526,7 +25371,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 53 */ +/* 52 */ /***/ function(module, exports, __webpack_require__) { @@ -25591,7 +25436,7 @@ return /******/ (function(modules) { // webpackBootstrap exports.parseGephi = parseGephi; /***/ }, -/* 54 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -25680,7 +25525,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 55 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { /** @@ -25738,7 +25583,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 56 */ +/* 55 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -26762,11 +26607,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */ +/* 56 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); + var Node = __webpack_require__(55); /** * @class Edge @@ -27955,7 +27800,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Edge; /***/ }, -/* 58 */ +/* 57 */ /***/ function(module, exports, __webpack_require__) { /** @@ -28101,16 +27946,16 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 59 */ +/* 58 */ /***/ function(module, exports, __webpack_require__) { - var PhysicsMixin = __webpack_require__(60); - var ClusterMixin = __webpack_require__(64); - var SectorsMixin = __webpack_require__(65); - var SelectionMixin = __webpack_require__(66); - var ManipulationMixin = __webpack_require__(67); - var NavigationMixin = __webpack_require__(68); - var HierarchicalLayoutMixin = __webpack_require__(69); + var PhysicsMixin = __webpack_require__(59); + var ClusterMixin = __webpack_require__(63); + var SectorsMixin = __webpack_require__(64); + var SelectionMixin = __webpack_require__(65); + var ManipulationMixin = __webpack_require__(66); + var NavigationMixin = __webpack_require__(67); + var HierarchicalLayoutMixin = __webpack_require__(68); /** * Load a mixin into the network object @@ -28305,13 +28150,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 60 */ +/* 59 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var RepulsionMixin = __webpack_require__(61); - var HierarchialRepulsionMixin = __webpack_require__(62); - var BarnesHutMixin = __webpack_require__(63); + var RepulsionMixin = __webpack_require__(60); + var HierarchialRepulsionMixin = __webpack_require__(61); + var BarnesHutMixin = __webpack_require__(62); /** * Toggling barnes Hut calculation on and off. @@ -29019,7 +28864,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 61 */ +/* 60 */ /***/ function(module, exports, __webpack_require__) { /** @@ -29083,7 +28928,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 62 */ +/* 61 */ /***/ function(module, exports, __webpack_require__) { /** @@ -29242,7 +29087,7 @@ return /******/ (function(modules) { // webpackBootstrap }; /***/ }, -/* 63 */ +/* 62 */ /***/ function(module, exports, __webpack_require__) { /** @@ -29647,7 +29492,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 64 */ +/* 63 */ /***/ function(module, exports, __webpack_require__) { /** @@ -30790,11 +30635,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 65 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); + var Node = __webpack_require__(55); /** * Creation of the SectorMixin var. @@ -31349,10 +31194,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 66 */ +/* 65 */ /***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(56); + var Node = __webpack_require__(55); /** * This function can be called from the _doInAllSectors function @@ -32063,12 +31908,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 67 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(56); - var Edge = __webpack_require__(57); + var Node = __webpack_require__(55); + var Edge = __webpack_require__(56); /** * clears the toolbar div element of children @@ -32664,7 +32509,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 68 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -32846,7 +32691,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 69 */ +/* 68 */ /***/ function(module, exports, __webpack_require__) { exports._resetLevels = function() { @@ -33262,6 +33107,163 @@ return /******/ (function(modules) { // webpackBootstrap }; +/***/ }, +/* 69 */ +/***/ function(module, exports, __webpack_require__) { + + var keycharm = __webpack_require__(50); + var Emitter = __webpack_require__(11); + var Hammer = __webpack_require__(19); + var util = __webpack_require__(1); + + /** + * Turn an element into an clickToUse element. + * When not active, the element has a transparent overlay. When the overlay is + * clicked, the mode is changed to active. + * When active, the element is displayed with a blue border around it, and + * the interactive contents of the element can be used. When clicked outside + * the element, the elements mode is changed to inactive. + * @param {Element} container + * @constructor + */ + function Activator(container) { + this.active = false; + + this.dom = { + container: container + }; + + this.dom.overlay = document.createElement('div'); + this.dom.overlay.className = 'overlay'; + + this.dom.container.appendChild(this.dom.overlay); + + this.hammer = Hammer(this.dom.overlay, {prevent_default: false}); + this.hammer.on('tap', this._onTapOverlay.bind(this)); + + // block all touch events (except tap) + var me = this; + var events = [ + 'touch', 'pinch', + 'doubletap', 'hold', + 'dragstart', 'drag', 'dragend', + 'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox + ]; + events.forEach(function (event) { + me.hammer.on(event, function (event) { + event.stopPropagation(); + }); + }); + + // attach a tap event to the window, in order to deactivate when clicking outside the timeline + this.windowHammer = Hammer(window, {prevent_default: false}); + this.windowHammer.on('tap', function (event) { + // deactivate when clicked outside the container + if (!_hasParent(event.target, container)) { + me.deactivate(); + } + }); + + if (this.keycharm !== undefined) { + this.keycharm.destroy(); + } + this.keycharm = keycharm(); + + // keycharm listener only bounded when active) + this.escListener = this.deactivate.bind(this); + } + + // turn into an event emitter + Emitter(Activator.prototype); + + // The currently active activator + Activator.current = null; + + /** + * Destroy the activator. Cleans up all created DOM and event listeners + */ + Activator.prototype.destroy = function () { + this.deactivate(); + + // remove dom + this.dom.overlay.parentNode.removeChild(this.dom.overlay); + + // cleanup hammer instances + this.hammer = null; + this.windowHammer = null; + // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory) + }; + + /** + * Activate the element + * Overlay is hidden, element is decorated with a blue shadow border + */ + Activator.prototype.activate = function () { + // we allow only one active activator at a time + if (Activator.current) { + Activator.current.deactivate(); + } + Activator.current = this; + + this.active = true; + this.dom.overlay.style.display = 'none'; + util.addClassName(this.dom.container, 'vis-active'); + + this.emit('change'); + this.emit('activate'); + + // ugly hack: bind ESC after emitting the events, as the Network rebinds all + // keyboard events on a 'change' event + this.keycharm.bind('esc', this.escListener); + }; + + /** + * Deactivate the element + * Overlay is displayed on top of the element + */ + Activator.prototype.deactivate = function () { + this.active = false; + this.dom.overlay.style.display = ''; + util.removeClassName(this.dom.container, 'vis-active'); + this.keycharm.unbind('esc', this.escListener); + + this.emit('change'); + this.emit('deactivate'); + }; + + /** + * Handle a tap event: activate the container + * @param event + * @private + */ + Activator.prototype._onTapOverlay = function (event) { + // activate the container + this.activate(); + event.stopPropagation(); + }; + + /** + * Test whether the element has the requested parent element somewhere in + * its chain of parent nodes. + * @param {HTMLElement} element + * @param {HTMLElement} parent + * @returns {boolean} Returns true when the parent is found somewhere in the + * chain of parent nodes. + * @private + */ + function _hasParent(element, parent) { + while (element) { + if (element === parent) { + return true + } + element = element.parentNode; + } + return false; + } + + module.exports = Activator; + + /***/ }, /* 70 */ /***/ function(module, exports, __webpack_require__) { diff --git a/docs/graph2d.html b/docs/graph2d.html index ab6aae17..31577896 100644 --- a/docs/graph2d.html +++ b/docs/graph2d.html @@ -943,6 +943,14 @@ Graph2d.off('rangechanged', onChange); Description Properties + + finishedRedraw + Fired after a redraw is complete. When moving the Graph2d around, this could be fired frequently. + + + none. + + rangechange diff --git a/docs/timeline.html b/docs/timeline.html index 05d970b6..9aff7f68 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -1000,8 +1000,16 @@ timeline.off('select', onSelect); Description Properties + + finishedRedraw + Fired after a redraw is complete. When moving the timeline around, this could be fired frequently. + + + none. + + - + rangechange Fired repeatedly when the user is dragging the timeline window. diff --git a/examples/timeline/03_performance.html b/examples/timeline/03_performance.html index de7588ab..665b473a 100644 --- a/examples/timeline/03_performance.html +++ b/examples/timeline/03_performance.html @@ -56,9 +56,6 @@ end: now.clone().add(11, 'days'), zoomMin: 1000 * 60 * 60 * 24, // a day zoomMax: 1000 * 60 * 60 * 24 * 30 * 3 // three months - //maxHeight: 300, - //height: '300px', - //orientation: 'top' }; var timeline = new vis.Timeline(container, items, options); diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index 7db48fa5..2037ec4d 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -595,6 +595,8 @@ Core.prototype.redraw = function() { // keep repainting until all sizes are settled this.redraw(); } + + this.emit("finishedRedraw"); }; // TODO: deprecated since version 1.1.0, remove some day