+ timeAxis.step |
number |
1 |
@@ -1280,7 +1285,7 @@ timeline.off('select', onSelect);
When the Timeline is configured to be editable (both options selectable and editable are true ), the user can:
- - Select an item by clicking it, and use ctrl+click to or shift+click to select multiple items
+ - Select an item by clicking it, and use ctrl+click to or shift+click to select multiple items (when
multiselect: true ).
- Move selected items by dragging them.
- Create a new item by double tapping on an empty space.
- Create a new range item by dragging on an empty space with the ctrl key down.
diff --git a/examples/timeline/02_manipulation.html b/examples/timeline/02_manipulation.html
index 8062c449..86e79682 100644
--- a/examples/timeline/02_manipulation.html
+++ b/examples/timeline/02_manipulation.html
@@ -44,6 +44,11 @@
start: '2014-01-10',
end: '2014-02-10',
height: '300px',
+
+ // allow selecting multiple items using ctrl+click, shift+click, or hold.
+ multiselect: true,
+
+ // allow manipulation of items
editable: true,
/* alternatively, enable/disable individual actions:
diff --git a/lib/DOMutil.js b/lib/DOMutil.js
index 5c78a4fb..31d2bfc5 100644
--- a/lib/DOMutil.js
+++ b/lib/DOMutil.js
@@ -150,7 +150,7 @@ exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer, labelObj)
}
if(group.options.drawPoints.styles !== undefined) {
- point.setAttributeNS(null, "style", 'vis-' + group.group.options.drawPoints.styles);
+ point.setAttributeNS(null, "style", group.group.options.drawPoints.styles);
}
point.setAttributeNS(null, "class", group.className + " vis-point");
//handle label
diff --git a/lib/network/dotparser.js b/lib/network/dotparser.js
index 65fc4042..c6145c32 100644
--- a/lib/network/dotparser.js
+++ b/lib/network/dotparser.js
@@ -769,7 +769,7 @@ function DOTToGraph (data) {
merge(graphEdge, dotEdge.attr);
graphEdge.style = (dotEdge.type === '->') ? 'arrow' : 'line';
return graphEdge;
- }
+ };
dotData.edges.forEach(function (dotEdge) {
var from, to;
diff --git a/lib/network/modules/Canvas.js b/lib/network/modules/Canvas.js
index c3a15e6c..45515c20 100644
--- a/lib/network/modules/Canvas.js
+++ b/lib/network/modules/Canvas.js
@@ -22,7 +22,7 @@ class Canvas {
width:'100%',
height:'100%',
autoResize: true
- }
+ };
util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
@@ -157,6 +157,8 @@ class Canvas {
// init hammer
this.hammer = new Hammer(this.frame.canvas);
this.hammer.get('pinch').set({enable: true});
+ // enable to get better response, todo: test on mobile.
+ //this.hammer.get('pan').set({threshold:2});
hammerUtil.onTouch(this.hammer, (event) => {this.body.eventListeners.onTouch(event)});
this.hammer.on('tap', (event) => {this.body.eventListeners.onTap(event)});
diff --git a/lib/network/modules/CanvasRenderer.js b/lib/network/modules/CanvasRenderer.js
index aba55bb5..dc5e5ee7 100644
--- a/lib/network/modules/CanvasRenderer.js
+++ b/lib/network/modules/CanvasRenderer.js
@@ -3,7 +3,7 @@ if (typeof window !== 'undefined') {
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
}
-var util = require('../../util');
+let util = require('../../util');
class CanvasRenderer {
@@ -24,7 +24,7 @@ class CanvasRenderer {
this.defaultOptions = {
hideEdgesOnDrag: false,
hideNodesOnDrag: false
- }
+ };
util.extend(this.options, this.defaultOptions);
this._determineBrowserMethod();
@@ -137,7 +137,7 @@ class CanvasRenderer {
this.body.emitter.emit("initRedraw");
this.redrawRequested = false;
- var ctx = this.canvas.frame.canvas.getContext('2d');
+ let ctx = this.canvas.frame.canvas.getContext('2d');
// when the container div was hidden, this fixes it back up!
if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
@@ -155,8 +155,8 @@ class CanvasRenderer {
ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
// clear the canvas
- var w = this.canvas.frame.canvas.clientWidth;
- var h = this.canvas.frame.canvas.clientHeight;
+ let w = this.canvas.frame.canvas.clientWidth;
+ let h = this.canvas.frame.canvas.clientHeight;
ctx.clearRect(0, 0, w, h);
@@ -191,8 +191,6 @@ class CanvasRenderer {
if (hidden === true) {
ctx.clearRect(0, 0, w, h);
}
-
-
}
@@ -204,13 +202,17 @@ class CanvasRenderer {
* @private
*/
_drawNodes(ctx, alwaysShow = false) {
- var nodes = this.body.nodes;
- var nodeIndices = this.body.nodeIndices;
- var node;
- var selected = [];
- var topLeft = this.canvas.DOMtoCanvas({x:0,y:0});
- var bottomRight = this.canvas.DOMtoCanvas({x:this.canvas.frame.canvas.clientWidth,y:this.canvas.frame.canvas.clientHeight});;
- var viewableArea = {top:topLeft.y,left:topLeft.x,bottom:bottomRight.y,right:bottomRight.x};
+ let nodes = this.body.nodes;
+ let nodeIndices = this.body.nodeIndices;
+ let node;
+ let selected = [];
+ let margin = 20;
+ let topLeft = this.canvas.DOMtoCanvas({x:-margin,y:-margin});
+ let bottomRight = this.canvas.DOMtoCanvas({
+ x: this.canvas.frame.canvas.clientWidth+margin,
+ y: this.canvas.frame.canvas.clientHeight+margin
+ });
+ let viewableArea = {top:topLeft.y,left:topLeft.x,bottom:bottomRight.y,right:bottomRight.x};
// draw unselected nodes;
@@ -245,9 +247,9 @@ class CanvasRenderer {
* @private
*/
_drawEdges(ctx) {
- var edges = this.body.edges;
- var edgeIndices = this.body.edgeIndices;
- var edge;
+ let edges = this.body.edges;
+ let edgeIndices = this.body.edgeIndices;
+ let edge;
for (let i = 0; i < edgeIndices.length; i++) {
edge = edges[edgeIndices[i]];
@@ -264,9 +266,9 @@ class CanvasRenderer {
* @private
*/
_drawControlNodes(ctx) {
- var edges = this.body.edges;
- var edgeIndices = this.body.edgeIndices;
- var edge;
+ let edges = this.body.edges;
+ let edgeIndices = this.body.edgeIndices;
+ let edge;
for (let i = 0; i < edgeIndices.length; i++) {
edge = edges[edgeIndices[i]];
@@ -281,7 +283,7 @@ class CanvasRenderer {
*/
_determineBrowserMethod() {
if (typeof window !== 'undefined') {
- var browserType = navigator.userAgent.toLowerCase();
+ let browserType = navigator.userAgent.toLowerCase();
this.requiresTimeout = false;
if (browserType.indexOf('msie 9.0') != -1) { // IE 9
this.requiresTimeout = true;
diff --git a/lib/network/modules/Clustering.js b/lib/network/modules/Clustering.js
index f5660509..fa6ef7cb 100644
--- a/lib/network/modules/Clustering.js
+++ b/lib/network/modules/Clustering.js
@@ -59,7 +59,7 @@ class ClusterEngine {
options = this._checkOptions(options);
let childNodesObj = {};
- let childEdgesObj = {}
+ let childEdgesObj = {};
// collect the nodes that will be in the cluster
for (let i = 0; i < this.body.nodeIndices.length; i++) {
@@ -143,7 +143,7 @@ class ClusterEngine {
let childNodesObj = {};
- let childEdgesObj = {}
+ let childEdgesObj = {};
let parentNodeId = node.id;
let parentClonedOptions = this._cloneOptions(parentNodeId);
childNodesObj[parentNodeId] = node;
@@ -388,7 +388,7 @@ class ClusterEngine {
return this.body.nodes[nodeId].isCluster === true;
}
else {
- console.log("Node does not exist.")
+ console.log("Node does not exist.");
return false;
}
}
@@ -426,8 +426,10 @@ class ClusterEngine {
// kill conditions
if (clusterNodeId === undefined) {throw new Error("No clusterNodeId supplied to openCluster.");}
if (this.body.nodes[clusterNodeId] === undefined) {throw new Error("The clusterNodeId supplied to openCluster does not exist.");}
- if (this.body.nodes[clusterNodeId].containedNodes === undefined) {console.log("The node:" + clusterNodeId + " is not a cluster."); return};
-
+ if (this.body.nodes[clusterNodeId].containedNodes === undefined) {
+ console.log("The node:" + clusterNodeId + " is not a cluster.");
+ return
+ }
let clusterNode = this.body.nodes[clusterNodeId];
let containedNodes = clusterNode.containedNodes;
let containedEdges = clusterNode.containedEdges;
@@ -492,7 +494,7 @@ class ClusterEngine {
if (from === true) {
edge.from = clusterStack[clusterStack.length - 1];
edge.fromId = clusterStack[clusterStack.length - 1].id;
- clusterStack.pop()
+ clusterStack.pop();
edge.fromArray = clusterStack;
}
else {
diff --git a/lib/network/modules/ConfigurationSystem.js b/lib/network/modules/ConfigurationSystem.js
index 50eff745..c2e57e10 100644
--- a/lib/network/modules/ConfigurationSystem.js
+++ b/lib/network/modules/ConfigurationSystem.js
@@ -27,7 +27,7 @@ class ConfigurationSystem {
enabled: false,
filter: true,
container: undefined
- }
+ };
util.extend(this.options, this.defaultOptions);
this.configureOptions = configureOptions;
@@ -371,7 +371,7 @@ class ConfigurationSystem {
value = value === undefined ? defaultColor : value;
div.onclick = () => {
this._showColorPicker(value,div,path);
- }
+ };
let label = this._makeLabel(path[path.length-1], path);
this._makeItem(path,label, div);
diff --git a/lib/network/modules/Groups.js b/lib/network/modules/Groups.js
index 05e6c116..60cf006e 100644
--- a/lib/network/modules/Groups.js
+++ b/lib/network/modules/Groups.js
@@ -34,13 +34,13 @@ class Groups {
{border: "#FFC0CB", background: "#FD5A77", highlight: {border: "#FFD1D9", background: "#FD5A77"}, hover: {border: "#FFD1D9", background: "#FD5A77"}}, // 18: pink
{border: "#C2FABC", background: "#74D66A", highlight: {border: "#E6FFE3", background: "#74D66A"}, hover: {border: "#E6FFE3", background: "#74D66A"}}, // 19: mint
- {border: "#EE0000", background: "#990000", highlight: {border: "#FF3333", background: "#BB0000"}, hover: {border: "#FF3333", background: "#BB0000"}}, // 20:bright red
+ {border: "#EE0000", background: "#990000", highlight: {border: "#FF3333", background: "#BB0000"}, hover: {border: "#FF3333", background: "#BB0000"}} // 20:bright red
];
this.options = {};
this.defaultOptions = {
useDefaultGroups: true
- }
+ };
util.extend(this.options, this.defaultOptions);
}
diff --git a/lib/network/modules/InteractionHandler.js b/lib/network/modules/InteractionHandler.js
index 21829305..90bc6354 100644
--- a/lib/network/modules/InteractionHandler.js
+++ b/lib/network/modules/InteractionHandler.js
@@ -47,7 +47,7 @@ class InteractionHandler {
navigationButtons: false,
tooltipDelay: 300,
zoomView: true
- }
+ };
util.extend(this.options,this.defaultOptions);
this.bindEventListeners()
@@ -478,7 +478,7 @@ class InteractionHandler {
// if the popup was not hidden above
if (this.popup.hidden === false) {
popupVisible = true;
- this.popup.setPosition(pointer.x + 3, pointer.y - 5)
+ this.popup.setPosition(pointer.x + 3, pointer.y - 5);
this.popup.show();
}
}
diff --git a/lib/network/modules/LayoutEngine.js b/lib/network/modules/LayoutEngine.js
index b78b84f2..2779493d 100644
--- a/lib/network/modules/LayoutEngine.js
+++ b/lib/network/modules/LayoutEngine.js
@@ -17,7 +17,7 @@ class LayoutEngine {
direction: 'UD', // UD, DU, LR, RL
sortMethod: 'hubsize' // hubsize, directed
}
- }
+ };
util.extend(this.options, this.defaultOptions);
this.hierarchicalLevels = {};
@@ -28,7 +28,7 @@ class LayoutEngine {
bindEventListeners() {
this.body.emitter.on('_dataChanged', () => {
this.setupHierarchicalLayout();
- })
+ });
this.body.emitter.on('_resetHierarchicalLayout', () => {
this.setupHierarchicalLayout();
});
diff --git a/lib/network/modules/ManipulationSystem.js b/lib/network/modules/ManipulationSystem.js
index f774a6ac..0fea0be1 100644
--- a/lib/network/modules/ManipulationSystem.js
+++ b/lib/network/modules/ManipulationSystem.js
@@ -46,7 +46,7 @@ class ManipulationSystem {
borderWidth: 2,
borderWidthSelected: 2
}
- }
+ };
util.extend(this.options, this.defaultOptions);
this.body.emitter.on('destroy', () => {this._clean();});
diff --git a/lib/network/modules/NodesHandler.js b/lib/network/modules/NodesHandler.js
index 2c49e1da..df40f59d 100644
--- a/lib/network/modules/NodesHandler.js
+++ b/lib/network/modules/NodesHandler.js
@@ -216,7 +216,7 @@ class NodesHandler {
for (let i = 0; i < ids.length; i++) {
id = ids[i];
let properties = this.body.data.nodes.get(id);
- let node = this.create(properties);;
+ let node = this.create(properties);
newNodes.push(node);
this.body.nodes[id] = node; // note: this may replace an existing node
}
@@ -386,7 +386,7 @@ class NodesHandler {
}
else if (edge.fromId === nodeId) {
if (nodeObj[edge.toId] === undefined) {
- nodeList.push(edge.toId)
+ nodeList.push(edge.toId);
nodeObj[edge.toId] = true;
}
}
diff --git a/lib/network/modules/PhysicsEngine.js b/lib/network/modules/PhysicsEngine.js
index 87a31b2b..be6546dd 100644
--- a/lib/network/modules/PhysicsEngine.js
+++ b/lib/network/modules/PhysicsEngine.js
@@ -60,7 +60,7 @@ class PhysicsEngine {
fit: true
},
timestep: 0.5
- }
+ };
util.extend(this.options, this.defaultOptions);
this.bindEventListeners();
@@ -80,7 +80,7 @@ class PhysicsEngine {
if (this.ready === true) {
this.startSimulation();
}
- })
+ });
this.body.emitter.on('stopSimulation', () => {this.stopSimulation();});
this.body.emitter.on('destroy', () => {
this.stopSimulation(false);
@@ -135,7 +135,7 @@ class PhysicsEngine {
else {
this.stabilized = false;
this.ready = true;
- this.body.emitter.emit('fit', {}, true)
+ this.body.emitter.emit('fit', {}, true);
this.startSimulation();
}
}
diff --git a/lib/network/modules/SelectionHandler.js b/lib/network/modules/SelectionHandler.js
index 5c51d277..df256b39 100644
--- a/lib/network/modules/SelectionHandler.js
+++ b/lib/network/modules/SelectionHandler.js
@@ -39,7 +39,7 @@ class SelectionHandler {
let selected = false;
if (this.options.selectable === true) {
this.unselectAll();
- let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);;
+ let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
if (obj !== undefined) {
selected = this.selectObject(obj);
}
@@ -51,7 +51,7 @@ class SelectionHandler {
selectAdditionalOnPoint(pointer) {
let selectionChanged = false;
if (this.options.selectable === true) {
- let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);;
+ let obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
if (obj !== undefined) {
selectionChanged = true;
@@ -73,7 +73,7 @@ class SelectionHandler {
properties['pointer'] = {
DOM: {x: pointer.x, y: pointer.y},
canvas: this.canvas.DOMtoCanvas(pointer)
- }
+ };
properties['event'] = event;
if (oldSelection !== undefined) {
diff --git a/lib/network/modules/components/Edge.js b/lib/network/modules/components/Edge.js
index 8dc20723..a4d38393 100644
--- a/lib/network/modules/components/Edge.js
+++ b/lib/network/modules/components/Edge.js
@@ -104,7 +104,7 @@ class Edge {
'to',
'title',
'value',
- 'width',
+ 'width'
];
// only deep extend the items in the field array. These do not have shorthand.
diff --git a/lib/network/modules/components/edges/util/EdgeBase.js b/lib/network/modules/components/edges/util/EdgeBase.js
index 6425b5b1..a18a5c07 100644
--- a/lib/network/modules/components/edges/util/EdgeBase.js
+++ b/lib/network/modules/components/edges/util/EdgeBase.js
@@ -1,4 +1,4 @@
-let util = require("../../../../../util")
+let util = require("../../../../../util");
class EdgeBase {
constructor(options, body, labelModule) {
@@ -198,7 +198,7 @@ class EdgeBase {
let radius = this.options.selfReferenceSize;
let pos, angle, distanceToBorder, distanceToPoint, difference;
let threshold = 0.05;
- let middle = (low + high) * 0.5
+ let middle = (low + high) * 0.5;
while (low <= high && iteration < maxIterations) {
middle = (low + high) * 0.5;
diff --git a/lib/network/modules/components/shared/Label.js b/lib/network/modules/components/shared/Label.js
index 58dfb97d..89961bf5 100644
--- a/lib/network/modules/components/shared/Label.js
+++ b/lib/network/modules/components/shared/Label.js
@@ -90,7 +90,7 @@ class Label {
break;
case 'bottom':
ctx.fillRect(-this.size.width * 0.5, lineMargin, this.size.width, this.size.height);
- break
+ break;
default:
ctx.fillRect(this.size.left, this.size.top, this.size.width, this.size.height);
break;
diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js
index 735b4770..906b829d 100644
--- a/lib/timeline/Core.js
+++ b/lib/timeline/Core.js
@@ -688,7 +688,7 @@ Core.prototype._redraw = function() {
// reposition the scrollable contents
var offset = this.props.scrollTop;
- if (options.orientation.item == 'bottom') {
+ if (options.orientation.item != 'top') {
offset += Math.max(this.props.centerContainer.height - this.props.center.height -
this.props.border.top - this.props.border.bottom, 0);
}
@@ -944,7 +944,7 @@ Core.prototype._updateScrollTop = function () {
if (scrollTopMin != this.props.scrollTopMin) {
// in case of bottom orientation, change the scrollTop such that the contents
// do not move relative to the time axis at the bottom
- if (this.options.orientation.item == 'bottom') {
+ if (this.options.orientation.item != 'top') {
this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin);
}
this.props.scrollTopMin = scrollTopMin;
diff --git a/lib/timeline/component/GraphGroup.js b/lib/timeline/component/GraphGroup.js
index 9c0291b1..9f58fdc8 100644
--- a/lib/timeline/component/GraphGroup.js
+++ b/lib/timeline/component/GraphGroup.js
@@ -138,7 +138,7 @@ GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, icon
path = DOMutil.getSVGElement("path", JSONcontainer, SVGcontainer);
path.setAttributeNS(null, "class", this.className);
if(this.style !== undefined) {
- path.setAttributeNS(null, "style", 'vis-' + this.style);
+ path.setAttributeNS(null, "style", this.style);
}
path.setAttributeNS(null, "d", "M" + x + ","+y+" L" + (x + iconWidth) + ","+y+"");
diff --git a/lib/timeline/component/ItemSet.js b/lib/timeline/component/ItemSet.js
index 3c6de0f4..487bdcf1 100644
--- a/lib/timeline/component/ItemSet.js
+++ b/lib/timeline/component/ItemSet.js
@@ -35,6 +35,8 @@ function ItemSet(body, options) {
groupOrder: null,
selectable: true,
+ multiselect: false,
+
editable: {
updateTime: false,
updateGroup: false,
@@ -226,7 +228,7 @@ ItemSet.prototype._create = function(){
* {Function} groupOrder
* A sorting function for ordering groups
* {Boolean} stack
- * If true (deafult), items will be stacked on
+ * If true (default), items will be stacked on
* top of each other.
* {Number} margin.axis
* Margin between the axis and the items in pixels.
@@ -244,6 +246,9 @@ ItemSet.prototype._create = function(){
* Set margin for both axis and items in pixels.
* {Boolean} selectable
* If true (default), items can be selected.
+ * {Boolean} multiselect
+ * If true, multiple items can be selected.
+ * False by default.
* {Boolean} editable
* Set all editable options to true or false
* {Boolean} editable.updateTime
@@ -272,7 +277,7 @@ ItemSet.prototype._create = function(){
ItemSet.prototype.setOptions = function(options) {
if (options) {
// copy all options that we know
- var fields = ['type', 'align', 'order', 'stack', 'selectable', 'groupOrder', 'dataAttributes', 'template','hide', 'snap'];
+ var fields = ['type', 'align', 'order', 'stack', 'selectable', 'multiselect', 'groupOrder', 'dataAttributes', 'template','hide', 'snap'];
util.selectiveExtend(fields, this.options, options);
if ('orientation' in options) {
@@ -1465,15 +1470,18 @@ ItemSet.prototype._onAddItem = function (event) {
ItemSet.prototype._onMultiSelectItem = function (event) {
if (!this.options.selectable) return;
- var selection,
- item = this.itemFromTarget(event);
+ var item = this.itemFromTarget(event);
if (item) {
- // multi select items
- selection = this.getSelection(); // current selection
+ // multi select items (if allowed)
+
+ var selection = this.options.multiselect
+ ? this.getSelection() // take current selection
+ : []; // deselect current selection
var shiftKey = event.srcEvent && event.srcEvent.shiftKey || false;
- if (shiftKey) {
+
+ if (shiftKey && this.options.multiselect) {
// select all items between the old selection and the tapped item
// determine the selection range
diff --git a/lib/timeline/component/LineGraph.js b/lib/timeline/component/LineGraph.js
index 5bb96daf..e38d7079 100644
--- a/lib/timeline/component/LineGraph.js
+++ b/lib/timeline/component/LineGraph.js
@@ -538,7 +538,9 @@ LineGraph.prototype.redraw = function(forceGraphUpdate) {
// calculate actual size and position
this.props.width = this.dom.frame.offsetWidth;
- this.props.height = this.body.domProps.centerContainer.height;
+ this.props.height = this.body.domProps.centerContainer.height
+ - this.body.domProps.border.top
+ - this.body.domProps.border.bottom;
// update the graph if there is no lastWidth or with, used for the initial draw
if (this.lastWidth === undefined && this.props.width) {
@@ -568,9 +570,9 @@ LineGraph.prototype.redraw = function(forceGraphUpdate) {
// update the height of the graph on each redraw of the graph.
if (this.updateSVGheight == true) {
- if (this.options.graphHeight != this.body.domProps.centerContainer.height + 'px') {
- this.options.graphHeight = this.body.domProps.centerContainer.height + 'px';
- this.svg.style.height = this.body.domProps.centerContainer.height + 'px';
+ if (this.options.graphHeight != this.props.height + 'px') {
+ this.options.graphHeight = this.props.height + 'px';
+ this.svg.style.height = this.props.height + 'px';
}
this.updateSVGheight = false;
}
diff --git a/lib/timeline/component/graph2d_types/line.js b/lib/timeline/component/graph2d_types/line.js
index 3a20ef14..d7f548aa 100644
--- a/lib/timeline/component/graph2d_types/line.js
+++ b/lib/timeline/component/graph2d_types/line.js
@@ -119,7 +119,7 @@ Line.prototype.draw = function (dataset, group, framework) {
path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg);
path.setAttributeNS(null, "class", group.className);
if(group.style !== undefined) {
- path.setAttributeNS(null, "style", 'vis-' + group.style);
+ path.setAttributeNS(null, "style", group.style);
}
// construct path from dataset
|