Browse Source

Implemented option `activatable` for Timeline and Graph2d

v3_develop
jos 10 years ago
parent
commit
0808f0a891
11 changed files with 268 additions and 102 deletions
  1. +2
    -0
      HISTORY.md
  2. +8
    -0
      docs/timeline.html
  3. +1
    -1
      examples/timeline/19_localization.html
  4. +72
    -0
      examples/timeline/20_activatable.html
  5. +1
    -0
      examples/timeline/index.html
  6. +1
    -0
      gulpfile.js
  7. +89
    -0
      lib/shared/Activator.js
  8. +14
    -0
      lib/shared/activator.css
  9. +80
    -2
      lib/timeline/Core.js
  10. +0
    -50
      lib/timeline/Graph2d.js
  11. +0
    -49
      lib/timeline/Timeline.js

+ 2
- 0
HISTORY.md View File

@ -10,6 +10,7 @@ http://visjs.org
- Fixed canceling moving an item to another group did not move the item
back to the original group.
- Added localization support.
- Implemented option `activatable`.
### Network
@ -23,6 +24,7 @@ http://visjs.org
- Added two examples showing the two additions above.
- Added 'customRange' for the Y axis and an example showing how it works.
- Added localization support.
- Implemented option `activatable`.
## 2014-08-14, version 3.2.0

+ 8
- 0
docs/timeline.html View File

@ -356,6 +356,14 @@ var options = {
<th>Description</th>
</tr>
<tr>
<td>activatable</td>
<td>boolean</td>
<td>false</td>
<td>When a Timeline is configured to be <code>activatable</code>, it will react to mouse and touch events only when active.
When active, a blue shadow border is displayed around the Timeline. The Timeline is set active by clicking on it, and is changed to inactive again by clicking outside the Timeline or by pressing the ESC key.</td>
</tr>
<tr>
<td>align</td>
<td>String</td>

+ 1
- 1
examples/timeline/19_localization.html View File

@ -10,7 +10,7 @@
}
</style>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment-with-langs.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.1/moment-with-locales.min.js"></script>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>

+ 72
- 0
examples/timeline/20_activatable.html View File

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Timeline | Activatable</title>
<style>
body, html {
font-family: arial, sans-serif;
font-size: 11pt;
}
#main {
width: 728px;
margin: 0 auto;
}
.container {
margin: 10px;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="main">
<h1>Activatable timeline</h1>
<p>
The following timelines are <code>activatable</code>: before you can scroll and drag in the timeline, you first have to click in the timeline to activate.
</p>
</div>
<script>
// create a dataset with items
// we specify the type of the fields `start` and `end` here to be strings
// containing an ISO date. The fields will be outputted as ISO dates
// automatically getting data from the DataSet via items.get().
var items = new vis.DataSet({
type: { start: 'ISODate', end: 'ISODate' }
});
// add items to the DataSet
items.add([
{id: 1, content: 'item 1<br>start', start: '2014-01-23'},
{id: 2, content: 'item 2', start: '2014-01-18'},
{id: 3, content: 'item 3', start: '2014-01-21'},
{id: 4, content: 'item 4', start: '2014-01-19', end: '2014-01-24'},
{id: 5, content: 'item 5', start: '2014-01-28', type:'point'},
{id: 6, content: 'item 6', start: '2014-01-26'}
]);
function createTimeline(main) {
var main = document.getElementById('main');
var container = document.createElement('div');
container.className = 'container';
main.appendChild(container);
var options = {
editable: true,
activatable: true
};
return new vis.Timeline(container, items, options);
}
var timelines = [];
for (var i = 0; i < 10; i++) {
timelines.push(createTimeline());
}
</script>
</body>
</html>

+ 1
- 0
examples/timeline/index.html View File

@ -31,6 +31,7 @@
<p><a href="17_data_serialization.html">17_data_serialization.html</a></p>
<p><a href="18_range_overflow.html">18_range_overflow.html</a></p>
<p><a href="19_localization.html">19_localization.html</a></p>
<p><a href="20_activatable.html">20_activatable.html</a></p>
<p><a href="requirejs/requirejs_example.html">requirejs_example.html</a></p>

+ 1
- 0
gulpfile.js View File

@ -80,6 +80,7 @@ gulp.task('bundle-js', ['clean'], function (cb) {
// bundle and minify css
gulp.task('bundle-css', ['clean'], function () {
var files = [
'./lib/shared/activator.css',
'./lib/timeline/component/css/timeline.css',
'./lib/timeline/component/css/panel.css',
'./lib/timeline/component/css/labelset.css',

+ 89
- 0
lib/shared/Activator.js View File

@ -0,0 +1,89 @@
var mousetrap = require('mousetrap');
var Hammer = require('../module/hammer');
var util = require('../util');
/**
* Turn an element into an activatable 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));
// 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', this.deactivate.bind(this));
// mousetrap listener only bounded when active)
this.escListener = this.deactivate.bind(this);
}
// 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;
};
/**
* 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');
mousetrap.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');
mousetrap.unbind('esc', this.escListener);
};
Activator.prototype._onTapOverlay = function (event) {
// activate the container
this.activate();
event.stopPropagation();
};
module.exports = Activator;

+ 14
- 0
lib/shared/activator.css View File

@ -0,0 +1,14 @@
.vis .overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* Must be displayed above for example selected Timeline items */
z-index: 10;
}
.vis-active {
box-shadow: 0 0 10px #86d5f8;
}

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

@ -8,6 +8,7 @@ var TimeAxis = require('./component/TimeAxis');
var CurrentTime = require('./component/CurrentTime');
var CustomTime = require('./component/CustomTime');
var ItemSet = require('./component/ItemSet');
var Activator = require('../shared/Activator');
/**
* Create a timeline visualization
@ -50,6 +51,7 @@ Core.prototype._create = function (container) {
this.dom.shadowTopRight = document.createElement('div');
this.dom.shadowBottomRight = document.createElement('div');
this.dom.root.className = 'vis timeline root';
this.dom.background.className = 'vispanel background';
this.dom.backgroundVertical.className = 'vispanel background vertical';
this.dom.backgroundHorizontal.className = 'vispanel background horizontal';
@ -112,7 +114,9 @@ Core.prototype._create = function (container) {
events.forEach(function (event) {
var listener = function () {
var args = [event].concat(Array.prototype.slice.call(arguments, 0));
me.emit.apply(me, args);
if (!me.activator || me.activator.active) {
me.emit.apply(me, args);
}
};
me.hammer.on(event, listener);
me.listeners[event] = listener;
@ -141,6 +145,67 @@ Core.prototype._create = function (container) {
container.appendChild(this.dom.root);
};
/**
* Set options. Options will be passed to all components loaded in the Timeline.
* @param {Object} [options]
* {String} orientation
* Vertical orientation for the Timeline,
* can be 'bottom' (default) or 'top'.
* {String | Number} width
* Width for the timeline, a number in pixels or
* a css string like '1000px' or '75%'. '100%' by default.
* {String | Number} height
* Fixed height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'. If undefined,
* The Timeline will automatically size such that
* its contents fit.
* {String | Number} minHeight
* Minimum height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'.
* {String | Number} maxHeight
* Maximum height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'.
* {Number | Date | String} start
* Start date for the visible window
* {Number | Date | String} end
* End date for the visible window
*/
Core.prototype.setOptions = function (options) {
if (options) {
// copy the known options
var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'activatable'];
util.selectiveExtend(fields, this.options, options);
if ('activatable' in options) {
if (options.activatable) {
this.activator = new Activator(this.dom.root);
}
else {
if (this.activator) {
this.activator.destroy();
delete this.activator;
}
}
}
// enable/disable autoResize
this._initAutoResize();
}
// propagate options to all components
this.components.forEach(function (component) {
component.setOptions(options);
});
// TODO: remove deprecation error one day (deprecated since version 0.8.0)
if (options && options.order) {
throw new Error('Option order is deprecated. There is no replacement for this feature.');
}
// redraw everything
this.redraw();
};
/**
* Destroy the Core, clean up all DOM elements and event listeners.
*/
@ -160,6 +225,12 @@ Core.prototype.destroy = function () {
}
this.dom = null;
// remove Activator
if (this.activator) {
this.activator.destroy();
delete this.activator;
}
// cleanup hammer touch events
for (var event in this.listeners) {
if (this.listeners.hasOwnProperty(event)) {
@ -321,7 +392,14 @@ Core.prototype.redraw = function() {
if (!dom) return; // when destroyed
// update class names
dom.root.className = 'vis timeline root ' + options.orientation;
if (options.orientation == 'top') {
util.addClassName(dom.root, 'top');
util.removeClassName(dom.root, 'bottom');
}
else {
util.removeClassName(dom.root, 'top');
util.addClassName(dom.root, 'bottom');
}
// update root width and height options
dom.root.style.maxHeight = util.option.asSize(options.maxHeight, '');

+ 0
- 50
lib/timeline/Graph2d.js View File

@ -105,56 +105,6 @@ function Graph2d (container, items, options, groups) {
// Extend the functionality from Core
Graph2d.prototype = new Core();
/**
* Set options. Options will be passed to all components loaded in the Graph2d.
* @param {Object} [options]
* {String} orientation
* Vertical orientation for the Graph2d,
* can be 'bottom' (default) or 'top'.
* {String | Number} width
* Width for the timeline, a number in pixels or
* a css string like '1000px' or '75%'. '100%' by default.
* {String | Number} height
* Fixed height for the Graph2d, a number in pixels or
* a css string like '400px' or '75%'. If undefined,
* The Graph2d will automatically size such that
* its contents fit.
* {String | Number} minHeight
* Minimum height for the Graph2d, a number in pixels or
* a css string like '400px' or '75%'.
* {String | Number} maxHeight
* Maximum height for the Graph2d, a number in pixels or
* a css string like '400px' or '75%'.
* {Number | Date | String} start
* Start date for the visible window
* {Number | Date | String} end
* End date for the visible window
*/
Graph2d.prototype.setOptions = function (options) {
if (options) {
// copy the known options
var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation'];
util.selectiveExtend(fields, this.options, options);
// enable/disable autoResize
this._initAutoResize();
}
// propagate options to all components
this.components.forEach(function (component) {
component.setOptions(options);
});
// TODO: remove deprecation error one day (deprecated since version 0.8.0)
if (options && options.order) {
throw new Error('Option order is deprecated. There is no replacement for this feature.');
}
// redraw everything
this.redraw();
};
/**
* Set items
* @param {vis.DataSet | Array | google.visualization.DataTable | null} items

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

@ -104,55 +104,6 @@ function Timeline (container, items, options) {
// Extend the functionality from Core
Timeline.prototype = new Core();
/**
* Set options. Options will be passed to all components loaded in the Timeline.
* @param {Object} [options]
* {String} orientation
* Vertical orientation for the Timeline,
* can be 'bottom' (default) or 'top'.
* {String | Number} width
* Width for the timeline, a number in pixels or
* a css string like '1000px' or '75%'. '100%' by default.
* {String | Number} height
* Fixed height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'. If undefined,
* The Timeline will automatically size such that
* its contents fit.
* {String | Number} minHeight
* Minimum height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'.
* {String | Number} maxHeight
* Maximum height for the Timeline, a number in pixels or
* a css string like '400px' or '75%'.
* {Number | Date | String} start
* Start date for the visible window
* {Number | Date | String} end
* End date for the visible window
*/
Timeline.prototype.setOptions = function (options) {
if (options) {
// copy the known options
var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation', 'activatable'];
util.selectiveExtend(fields, this.options, options);
// enable/disable autoResize
this._initAutoResize();
}
// propagate options to all components
this.components.forEach(function (component) {
component.setOptions(options);
});
// TODO: remove deprecation error one day (deprecated since version 0.8.0)
if (options && options.order) {
throw new Error('Option order is deprecated. There is no replacement for this feature.');
}
// redraw everything
this.redraw();
};
/**
* Set items
* @param {vis.DataSet | Array | google.visualization.DataTable | null} items

Loading…
Cancel
Save