diff --git a/HISTORY.md b/HISTORY.md
index f53eab11..9a28ac26 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -14,6 +14,9 @@ http://visjs.org
- Fixed #1334 (again): Network now ignores scroll when interaction:zoomView is false.
- Fixed #1588: destroy now unsubscribed from the dataset.
- Fixed #1584: Navigation buttons broken.
+- Fixed #1596: correct clean up of manipulation dom elements.
+- Fixed #1594: bug in hierarchical layout.
+- Fixed #1597: Allow zero borders and addressed scaling artifacts.
### Timeline
diff --git a/dist/vis.js b/dist/vis.js
index f4193f82..e31564d9 100644
--- a/dist/vis.js
+++ b/dist/vis.js
@@ -5,7 +5,7 @@
* A dynamic, browser-based visualization library.
*
* @version 4.12.1-SNAPSHOT
- * @date 2016-01-19
+ * @date 2016-01-23
*
* @license
* Copyright (C) 2011-2016 Almende B.V, http://almende.com
@@ -10648,6 +10648,27 @@ return /******/ (function(modules) { // webpackBootstrap
me.emit('contextmenu', me.getEventProperties(event));
};
+ //Single time autoscale/fit
+ this.fitDone = false;
+ this.on('changed', function () {
+ if (this.itemsData == null) return;
+ if (!me.fitDone) {
+ me.fitDone = true;
+ if (me.options.start != undefined || me.options.end != undefined) {
+ if (me.options.start == undefined || me.options.end == undefined) {
+ var range = me.getItemRange();
+ }
+
+ var start = me.options.start != undefined ? me.options.start : range.min;
+ var end = me.options.end != undefined ? me.options.end : range.max;
+
+ me.setWindow(start, end, { animation: false });
+ } else {
+ me.fit({ animation: false });
+ }
+ }
+ });
+
// apply options
if (options) {
this.setOptions(options);
@@ -10720,8 +10741,6 @@ return /******/ (function(modules) { // webpackBootstrap
* @param {vis.DataSet | Array | null} items
*/
Timeline.prototype.setItems = function (items) {
- var initialLoad = this.itemsData == null;
-
// convert to type DataSet when needed
var newDataSet;
if (!items) {
@@ -10742,20 +10761,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.itemsData = newDataSet;
this.itemSet && this.itemSet.setItems(newDataSet);
- if (initialLoad) {
- if (this.options.start != undefined || this.options.end != undefined) {
- if (this.options.start == undefined || this.options.end == undefined) {
- var range = this.getItemRange();
- }
-
- var start = this.options.start != undefined ? this.options.start : range.min;
- var end = this.options.end != undefined ? this.options.end : range.max;
-
- this.setWindow(start, end, { animation: false });
- } else {
- this.fit({ animation: false });
- }
- }
+ this.body.emitter.emit('_change', { queue: true });
};
/**
@@ -10935,6 +10941,7 @@ return /******/ (function(modules) { // webpackBootstrap
factor = interval / _this.props.center.width;
util.forEach(_this.itemSet.items, (function (item) {
item.show();
+ item.repositionX();
var start = getStart(item);
var end = getEnd(item);
@@ -14611,23 +14618,14 @@ return /******/ (function(modules) { // webpackBootstrap
*/
exports.onTouch = function (hammer, callback) {
callback.inputHandler = function (event) {
- if (event.isFirst && !isTouching) {
+ if (event.isFirst) {
callback(event);
-
- isTouching = true;
- setTimeout(function () {
- isTouching = false;
- }, 0);
}
};
hammer.on('hammer.input', callback.inputHandler);
};
- // isTouching is true while a touch action is being emitted
- // this is a hack to prevent `touch` from being fired twice
- var isTouching = false;
-
/**
* Register a release event, taking place after a gesture
* @param {Hammer} hammer A hammer instance
@@ -14635,23 +14633,14 @@ return /******/ (function(modules) { // webpackBootstrap
*/
exports.onRelease = function (hammer, callback) {
callback.inputHandler = function (event) {
- if (event.isFinal && !isReleasing) {
+ if (event.isFinal) {
callback(event);
-
- isReleasing = true;
- setTimeout(function () {
- isReleasing = false;
- }, 0);
}
};
return hammer.on('hammer.input', callback.inputHandler);
};
- // isReleasing is true while a release action is being emitted
- // this is a hack to prevent `release` from being fired twice
- var isReleasing = false;
-
/**
* Unregister a touch event, taking place before a gesture
* @param {Hammer} hammer A hammer instance
@@ -15299,13 +15288,15 @@ return /******/ (function(modules) { // webpackBootstrap
this.dom.rightContainer.appendChild(this.dom.shadowBottomRight);
this.on('rangechange', (function () {
- this._redraw(); // this allows overriding the _redraw method
+ if (this.initialDrawDone) {
+ this._redraw(); // this allows overriding the _redraw method
+ }
}).bind(this));
this.on('touch', this._onTouch.bind(this));
this.on('pan', this._onDrag.bind(this));
var me = this;
- this.on('change', function (properties) {
+ this.on('_change', function (properties) {
if (properties && properties.queue == true) {
// redraw once on next tick
if (!me._redrawTimer) {
@@ -15385,6 +15376,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.touch = {};
this.redrawCount = 0;
+ this.initialDrawDone = false;
// attach the root panel to the provided container
if (!container) throw new Error('No container provided');
@@ -15515,11 +15507,11 @@ return /******/ (function(modules) { // webpackBootstrap
// override redraw with a throttled version
if (!this._origRedraw) {
this._origRedraw = this._redraw.bind(this);
+ this._redraw = util.throttle(this._origRedraw, this.options.throttleRedraw);
+ } else {
+ // Not the initial run: redraw everything
+ this._redraw();
}
- this._redraw = util.throttle(this._origRedraw, this.options.throttleRedraw);
-
- // redraw everything
- this._redraw();
};
/**
@@ -15816,12 +15808,13 @@ return /******/ (function(modules) { // webpackBootstrap
* @protected
*/
Core.prototype._redraw = function () {
+ this.redrawCount++;
var resized = false;
var options = this.options;
var props = this.props;
var dom = this.dom;
- if (!dom) return; // when destroyed
+ if (!dom || !dom.container || dom.container.clientWidth == 0) return; // when destroyed, or invisible
DateUtil.updateHiddenDates(this.options.moment, this.body, this.options.hiddenDates);
@@ -15957,17 +15950,21 @@ return /******/ (function(modules) { // webpackBootstrap
this.components.forEach(function (component) {
resized = component.redraw() || resized;
});
+ var MAX_REDRAW = 5;
if (resized) {
- // keep repainting until all sizes are settled
- var MAX_REDRAWS = 3; // maximum number of consecutive redraws
- if (this.redrawCount < MAX_REDRAWS) {
- this.redrawCount++;
- this._redraw();
+ if (this.redrawCount < MAX_REDRAW) {
+ this.body.emitter.emit('_change');
+ return;
} else {
console.log('WARNING: infinite loop in redraw?');
}
+ } else {
this.redrawCount = 0;
}
+ this.initialDrawDone = true;
+
+ //Emit public 'changed' event for UI updates, see issue #1592
+ this.body.emitter.emit("changed");
};
// TODO: deprecated since version 1.1.0, remove some day
@@ -16092,7 +16089,7 @@ return /******/ (function(modules) { // webpackBootstrap
me.props.lastWidth = me.dom.root.offsetWidth;
me.props.lastHeight = me.dom.root.offsetHeight;
- me.emit('change');
+ me.body.emitter.emit('_change');
}
}
};
@@ -16100,6 +16097,12 @@ return /******/ (function(modules) { // webpackBootstrap
// add event listener to window resize
util.addEventListener(window, 'resize', this._onResize);
+ //Prevent initial unnecessary redraw
+ if (me.dom.root) {
+ me.props.lastWidth = me.dom.root.offsetWidth;
+ me.props.lastHeight = me.dom.root.offsetHeight;
+ }
+
this.watchTimer = setInterval(this._onResize, 1000);
};
@@ -16997,7 +17000,7 @@ return /******/ (function(modules) { // webpackBootstrap
// update the order of all items in each group
this._order();
- this.body.emitter.emit('change', { queue: true });
+ this.body.emitter.emit('_change', { queue: true });
};
/**
@@ -17102,7 +17105,7 @@ return /******/ (function(modules) { // webpackBootstrap
this._order();
this.stackDirty = true; // force re-stacking of all items next redraw
- this.body.emitter.emit('change', { queue: true });
+ this.body.emitter.emit('_change', { queue: true });
};
/**
@@ -17132,7 +17135,7 @@ return /******/ (function(modules) { // webpackBootstrap
// update order
this._order();
this.stackDirty = true; // force re-stacking of all items next redraw
- this.body.emitter.emit('change', { queue: true });
+ this.body.emitter.emit('_change', { queue: true });
}
};
@@ -17201,7 +17204,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
});
- this.body.emitter.emit('change', { queue: true });
+ this.body.emitter.emit('_change', { queue: true });
};
/**
@@ -17222,7 +17225,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.markDirty();
- this.body.emitter.emit('change', { queue: true });
+ this.body.emitter.emit('_change', { queue: true });
};
/**
@@ -17585,7 +17588,7 @@ return /******/ (function(modules) { // webpackBootstrap
}).bind(this));
this.stackDirty = true; // force re-stacking of all items next redraw
- this.body.emitter.emit('change');
+ this.body.emitter.emit('_change');
}
};
@@ -17636,7 +17639,7 @@ return /******/ (function(modules) { // webpackBootstrap
// force re-stacking of all items next redraw
me.stackDirty = true;
- me.body.emitter.emit('change');
+ me.body.emitter.emit('_change');
});
} else {
// update existing item
@@ -17651,7 +17654,7 @@ return /******/ (function(modules) { // webpackBootstrap
props.item.setData(props.data);
me.stackDirty = true; // force re-stacking of all items next redraw
- me.body.emitter.emit('change');
+ me.body.emitter.emit('_change');
}
});
}
@@ -24269,6 +24272,7 @@ return /******/ (function(modules) { // webpackBootstrap
// item set
this.linegraph = new LineGraph(this.body);
+
this.components.push(this.linegraph);
this.itemsData = null; // DataSet
@@ -24297,9 +24301,8 @@ return /******/ (function(modules) { // webpackBootstrap
// create itemset
if (items) {
this.setItems(items);
- } else {
- this._redraw();
}
+ this._redraw();
}
// Extend the functionality from Core
@@ -24346,7 +24349,6 @@ return /******/ (function(modules) { // webpackBootstrap
if (this.options.start != undefined || this.options.end != undefined) {
var start = this.options.start != undefined ? this.options.start : null;
var end = this.options.end != undefined ? this.options.end : null;
-
this.setWindow(start, end, { animation: false });
} else {
this.fit({ animation: false });
@@ -24581,6 +24583,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.abortedGraphUpdate = false;
this.updateSVGheight = false;
this.updateSVGheightOnResize = false;
+ this.forceGraphUpdate = true;
var me = this;
this.itemsData = null; // DataSet
@@ -24620,17 +24623,18 @@ return /******/ (function(modules) { // webpackBootstrap
this.svgElements = {};
this.setOptions(options);
this.groupsUsingDefaultStyles = [0];
- this.COUNTER = 0;
this.body.emitter.on('rangechanged', function () {
me.lastStart = me.body.range.start;
me.svg.style.left = util.option.asSize(-me.props.width);
- me.redraw.call(me, true);
+
+ me.forceGraphUpdate = true;
+ //Is this local redraw necessary? (Core also does a change event!)
+ me.redraw.call(me);
});
// create the HTML DOM
this._create();
this.framework = { svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups };
- this.body.emitter.emit('change');
}
LineGraph.prototype = new Component();
@@ -24672,7 +24676,7 @@ return /******/ (function(modules) { // webpackBootstrap
LineGraph.prototype.setOptions = function (options) {
if (options) {
var fields = ['sampling', 'defaultGroup', 'stack', 'height', 'graphHeight', 'yAxisOrientation', 'style', 'barChart', 'dataAxis', 'sort', 'groups'];
- if (options.graphHeight === undefined && options.height !== undefined && this.body.domProps.centerContainer.height !== undefined) {
+ if (options.graphHeight === undefined && options.height !== undefined) {
this.updateSVGheight = true;
this.updateSVGheightOnResize = true;
} else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) {
@@ -24722,7 +24726,9 @@ return /******/ (function(modules) { // webpackBootstrap
// this is used to redraw the graph if the visibility of the groups is changed.
if (this.dom.frame) {
- this.redraw(true);
+ //not on initial run?
+ this.forceGraphUpdate = true;
+ this.body.emitter.emit("_change", { queue: true });
}
};
@@ -24835,7 +24841,6 @@ return /******/ (function(modules) { // webpackBootstrap
LineGraph.prototype._onUpdate = function (ids) {
this._updateAllGroupData();
- this.redraw(true);
};
LineGraph.prototype._onAdd = function (ids) {
this._onUpdate(ids);
@@ -24845,7 +24850,6 @@ return /******/ (function(modules) { // webpackBootstrap
};
LineGraph.prototype._onUpdateGroups = function (groupIds) {
this._updateAllGroupData();
- this.redraw(true);
};
LineGraph.prototype._onAddGroups = function (groupIds) {
this._onUpdateGroups(groupIds);
@@ -24860,7 +24864,8 @@ return /******/ (function(modules) { // webpackBootstrap
for (var i = 0; i < groupIds.length; i++) {
this._removeGroup(groupIds[i]);
}
- this.redraw(true);
+ this.forceGraphUpdate = true;
+ this.body.emitter.emit("_change", { queue: true });
};
/**
@@ -24905,9 +24910,15 @@ return /******/ (function(modules) { // webpackBootstrap
if (this.groups[groupId].options.yAxisOrientation == 'right') {
this.yAxisRight.updateGroup(groupId, this.groups[groupId]);
this.legendRight.updateGroup(groupId, this.groups[groupId]);
+ //If yAxisOrientation changed, clean out the group from the other axis.
+ this.yAxisLeft.removeGroup(groupId);
+ this.legendLeft.removeGroup(groupId);
} else {
this.yAxisLeft.updateGroup(groupId, this.groups[groupId]);
this.legendLeft.updateGroup(groupId, this.groups[groupId]);
+ //If yAxisOrientation changed, clean out the group from the other axis.
+ this.yAxisRight.removeGroup(groupId);
+ this.legendRight.removeGroup(groupId);
}
}
this.legendLeft.redraw();
@@ -24983,6 +24994,8 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
}
+ this.forceGraphUpdate = true;
+ this.body.emitter.emit("_change", { queue: true });
}
};
@@ -24990,16 +25003,16 @@ return /******/ (function(modules) { // webpackBootstrap
* Redraw the component, mandatory function
* @return {boolean} Returns true if the component is resized
*/
- LineGraph.prototype.redraw = function (forceGraphUpdate) {
+ LineGraph.prototype.redraw = function () {
var resized = false;
// calculate actual size and position
this.props.width = this.dom.frame.offsetWidth;
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
+ // update the graph if there is no lastWidth or width, used for the initial draw
if (this.lastWidth === undefined && this.props.width) {
- forceGraphUpdate = true;
+ this.forceGraphUpdate = true;
}
// check if this component is resized
@@ -25034,8 +25047,9 @@ return /******/ (function(modules) { // webpackBootstrap
}
// zoomed is here to ensure that animations are shown correctly.
- if (resized == true || zoomed == true || this.abortedGraphUpdate == true || forceGraphUpdate == true) {
+ if (resized == true || zoomed == true || this.abortedGraphUpdate == true || this.forceGraphUpdate == true) {
resized = this._updateGraph() || resized;
+ this.forceGraphUpdate = false;
} else {
// move the whole svg while dragging
if (this.lastStart != 0) {
@@ -25048,7 +25062,6 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
}
-
this.legendLeft.redraw();
this.legendRight.redraw();
return resized;
@@ -25114,96 +25127,93 @@ return /******/ (function(modules) { // webpackBootstrap
this._getYRanges(groupIds, groupsData, groupRanges);
// update the Y axis first, we use this data to draw at the correct Y points
- // changeCalled is required to clean the SVG on a change emit.
changeCalled = this._updateYAxis(groupIds, groupRanges);
- var MAX_CYCLES = 5;
- if (changeCalled == true && this.COUNTER < MAX_CYCLES) {
+
+ // at changeCalled, abort this update cycle as the graph needs another update with new Width input from the Redraw container.
+ // Cleanup SVG elements on abort.
+ if (changeCalled == true) {
DOMutil.cleanupElements(this.svgElements);
this.abortedGraphUpdate = true;
- this.COUNTER++;
- this.body.emitter.emit('change');
return true;
- } else {
- if (this.COUNTER > MAX_CYCLES) {
- console.log("WARNING: there may be an infinite loop in the _updateGraph emitter cycle.");
- }
- this.COUNTER = 0;
- this.abortedGraphUpdate = false;
-
- // With the yAxis scaled correctly, use this to get the Y values of the points.
- var below = undefined;
- for (i = 0; i < groupIds.length; i++) {
- group = this.groups[groupIds[i]];
- if (this.options.stack === true && this.options.style === 'line') {
- if (group.options.excludeFromStacking == undefined || !group.options.excludeFromStacking) {
- if (below != undefined) {
- this._stack(groupsData[group.id], groupsData[below.id]);
- if (group.options.shaded.enabled == true && group.options.shaded.orientation !== "group") {
- if (group.options.shaded.orientation == "top" && below.options.shaded.orientation !== "group") {
- below.options.shaded.orientation = "group";
- below.options.shaded.groupId = group.id;
- } else {
- group.options.shaded.orientation = "group";
- group.options.shaded.groupId = below.id;
- }
+ }
+ this.abortedGraphUpdate = false;
+
+ // With the yAxis scaled correctly, use this to get the Y values of the points.
+ var below = undefined;
+ for (i = 0; i < groupIds.length; i++) {
+ group = this.groups[groupIds[i]];
+ if (this.options.stack === true && this.options.style === 'line') {
+ if (group.options.excludeFromStacking == undefined || !group.options.excludeFromStacking) {
+ if (below != undefined) {
+ this._stack(groupsData[group.id], groupsData[below.id]);
+ if (group.options.shaded.enabled == true && group.options.shaded.orientation !== "group") {
+ if (group.options.shaded.orientation == "top" && below.options.shaded.orientation !== "group") {
+ below.options.shaded.orientation = "group";
+ below.options.shaded.groupId = group.id;
+ } else {
+ group.options.shaded.orientation = "group";
+ group.options.shaded.groupId = below.id;
}
}
- below = group;
}
+ below = group;
}
- this._convertYcoordinates(groupsData[groupIds[i]], group);
}
+ this._convertYcoordinates(groupsData[groupIds[i]], group);
+ }
- //Precalculate paths and draw shading if appropriate. This will make sure the shading is always behind any lines.
- var paths = {};
- for (i = 0; i < groupIds.length; i++) {
- group = this.groups[groupIds[i]];
- if (group.options.style === 'line' && group.options.shaded.enabled == true) {
- var dataset = groupsData[groupIds[i]];
- if (!paths.hasOwnProperty(groupIds[i])) {
- paths[groupIds[i]] = Lines.calcPath(dataset, group);
+ //Precalculate paths and draw shading if appropriate. This will make sure the shading is always behind any lines.
+ var paths = {};
+ for (i = 0; i < groupIds.length; i++) {
+ group = this.groups[groupIds[i]];
+ if (group.options.style === 'line' && group.options.shaded.enabled == true) {
+ var dataset = groupsData[groupIds[i]];
+ if (dataset == null || dataset.length == 0) {
+ continue;
+ }
+ if (!paths.hasOwnProperty(groupIds[i])) {
+ paths[groupIds[i]] = Lines.calcPath(dataset, group);
+ }
+ if (group.options.shaded.orientation === "group") {
+ var subGroupId = group.options.shaded.groupId;
+ if (groupIds.indexOf(subGroupId) === -1) {
+ console.log(group.id + ": Unknown shading group target given:" + subGroupId);
+ continue;
}
- if (group.options.shaded.orientation === "group") {
- var subGroupId = group.options.shaded.groupId;
- if (groupIds.indexOf(subGroupId) === -1) {
- console.log(group.id + ": Unknown shading group target given:" + subGroupId);
- continue;
- }
- if (!paths.hasOwnProperty(subGroupId)) {
- paths[subGroupId] = Lines.calcPath(groupsData[subGroupId], this.groups[subGroupId]);
- }
- Lines.drawShading(paths[groupIds[i]], group, paths[subGroupId], this.framework);
- } else {
- Lines.drawShading(paths[groupIds[i]], group, undefined, this.framework);
+ if (!paths.hasOwnProperty(subGroupId)) {
+ paths[subGroupId] = Lines.calcPath(groupsData[subGroupId], this.groups[subGroupId]);
}
+ Lines.drawShading(paths[groupIds[i]], group, paths[subGroupId], this.framework);
+ } else {
+ Lines.drawShading(paths[groupIds[i]], group, undefined, this.framework);
}
}
+ }
- // draw the groups, calculating paths if still necessary.
- Bars.draw(groupIds, groupsData, this.framework);
- for (i = 0; i < groupIds.length; i++) {
- group = this.groups[groupIds[i]];
- if (groupsData[groupIds[i]].length > 0) {
- switch (group.options.style) {
- case "line":
- if (!paths.hasOwnProperty(groupIds[i])) {
- paths[groupIds[i]] = Lines.calcPath(groupsData[groupIds[i]], group);
- }
- Lines.draw(paths[groupIds[i]], group, this.framework);
- //explicit no break;
- case "point":
- //explicit no break;
- case "points":
- if (group.options.style == "point" || group.options.style == "points" || group.options.drawPoints.enabled == true) {
- Points.draw(groupsData[groupIds[i]], group, this.framework);
- }
- break;
- case "bar":
- // bar needs to be drawn enmasse
- //explicit no break
- default:
- //do nothing...
- }
+ // draw the groups, calculating paths if still necessary.
+ Bars.draw(groupIds, groupsData, this.framework);
+ for (i = 0; i < groupIds.length; i++) {
+ group = this.groups[groupIds[i]];
+ if (groupsData[groupIds[i]].length > 0) {
+ switch (group.options.style) {
+ case "line":
+ if (!paths.hasOwnProperty(groupIds[i])) {
+ paths[groupIds[i]] = Lines.calcPath(groupsData[groupIds[i]], group);
+ }
+ Lines.draw(paths[groupIds[i]], group, this.framework);
+ //explicit no break;
+ case "point":
+ //explicit no break;
+ case "points":
+ if (group.options.style == "point" || group.options.style == "points" || group.options.drawPoints.enabled == true) {
+ Points.draw(groupsData[groupIds[i]], group, this.framework);
+ }
+ break;
+ case "bar":
+ // bar needs to be drawn enmasse
+ //explicit no break
+ default:
+ //do nothing...
}
}
}
@@ -25572,14 +25582,14 @@ return /******/ (function(modules) { // webpackBootstrap
left: {
range: { min: undefined, max: undefined },
format: function format(value) {
- return '' + value.toPrecision(3);
+ return '' + Number.parseFloat(value.toPrecision(3));
},
title: { text: undefined, style: undefined }
},
right: {
range: { min: undefined, max: undefined },
format: function format(value) {
- return '' + value.toPrecision(3);
+ return '' + Number.parseFloat(value.toPrecision(3));
},
title: { text: undefined, style: undefined }
}
@@ -25639,6 +25649,9 @@ return /******/ (function(modules) { // webpackBootstrap
};
DataAxis.prototype.updateGroup = function (label, graphOptions) {
+ if (!this.groups.hasOwnProperty(label)) {
+ this.amountOfGroups += 1;
+ }
this.groups[label] = graphOptions;
};
@@ -25873,9 +25886,8 @@ return /******/ (function(modules) { // webpackBootstrap
var orientation = this.options['orientation'];
// get the range for the slaved axis
- var step;
+ var step, stepSize, rangeStart, rangeEnd;
if (this.master === false) {
- var stepSize, rangeStart, rangeEnd, minimumStep;
if (this.zeroCrossing !== -1 && this.options.alignZeros === true) {
if (this.range.end > 0) {
stepSize = this.range.end / this.zeroCrossing; // size of one step
@@ -25891,13 +25903,12 @@ return /******/ (function(modules) { // webpackBootstrap
rangeStart = this.range.start;
rangeEnd = this.range.end;
}
- minimumStep = this.stepPixels;
} else {
// calculate range and step (step such that we have space for 7 characters per label)
- minimumStep = this.props.majorCharHeight;
rangeStart = this.range.start;
rangeEnd = this.range.end;
}
+ var minimumStep = this.props.majorCharHeight;
this.step = step = new DataStep(rangeStart, rangeEnd, minimumStep, this.dom.frame.offsetHeight, this.options[this.options.orientation].range, this.options[this.options.orientation].format, this.master === false && this.options.alignZeros // does the step have to align zeros? only if not master and the options is on
);
@@ -26172,9 +26183,7 @@ return /******/ (function(modules) { // webpackBootstrap
function DataStep(start, end, minimumStep, containerHeight, customRange, formattingFunction, alignZeros) {
// variables
- this.current = 0;
-
- this.autoScale = true;
+ this.current = -1;
this.stepIndex = 0;
this.step = 1;
this.scale = 1;
@@ -26182,7 +26191,6 @@ return /******/ (function(modules) { // webpackBootstrap
this.marginStart;
this.marginEnd;
- this.deadSpace = 0;
this.majorSteps = [1, 2, 5, 10];
this.minorSteps = [0.25, 0.5, 1, 2];
@@ -26203,17 +26211,17 @@ return /******/ (function(modules) { // webpackBootstrap
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/
DataStep.prototype.setRange = function (start, end, minimumStep, containerHeight, customRange) {
+ if (customRange === undefined) {
+ customRange = {};
+ }
+
this._start = customRange.min === undefined ? start : customRange.min;
this._end = customRange.max === undefined ? end : customRange.max;
if (this._start === this._end) {
this._start = customRange.min === undefined ? this._start - 0.75 : this._start;
- this._end = customRange.max === undefined ? this._end + 1 : this._end;;
+ this._end = customRange.max === undefined ? this._end + 1 : this._end;
}
-
- if (this.autoScale === true) {
- this.setMinimumStep(minimumStep, containerHeight);
- }
-
+ this.setMinimumStep(minimumStep, containerHeight);
this.setFirst(customRange);
};
@@ -26276,9 +26284,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.marginEnd += this.marginEnd % this.step;
}
- this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart;
this.marginRange = this.marginEnd - this.marginStart;
-
this.current = this.marginEnd;
};
@@ -26328,6 +26334,7 @@ return /******/ (function(modules) { // webpackBootstrap
DataStep.prototype.getCurrent = function () {
// prevent round-off errors when close to zero
var current = Math.abs(this.current) < this.step / 2 ? 0 : this.current;
+
var returnValue = current;
if (typeof this.formattingFunction === 'function') {
return this.formattingFunction(current);
@@ -26382,7 +26389,7 @@ return /******/ (function(modules) { // webpackBootstrap
*/
function GraphGroup(group, groupId, options, groupsUsingDefaultStyles) {
this.id = groupId;
- var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation', 'zIndex'];
+ var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation', 'zIndex', 'excludeFromStacking', 'excludeFromLegend'];
this.options = util.selectiveBridgeObject(fields, options);
this.usingDefaultStyle = group.className === undefined;
this.groupsUsingDefaultStyles = groupsUsingDefaultStyles;
@@ -26430,7 +26437,7 @@ return /******/ (function(modules) { // webpackBootstrap
*/
GraphGroup.prototype.setOptions = function (options) {
if (options !== undefined) {
- var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'excludeFromLegend', 'excludeFromStacking', 'zIndex'];
+ var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'zIndex', 'excludeFromStacking', 'excludeFromLegend'];
util.selectiveDeepExtend(fields, this.options, options);
// if the group's drawPoints is a function delegate the callback to the onRender property
@@ -26636,7 +26643,7 @@ return /******/ (function(modules) { // webpackBootstrap
drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
intersections[key].resolved += 1;
- if (group.options.stack === true) {
+ if (group.options.stack === true && group.options.excludeFromStacking !== true) {
if (combinedData[i].screen_y < group.zeroPosition) {
heightOffset = intersections[key].accumulatedNegative;
intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].screen_y;
@@ -29862,11 +29869,14 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
this.updateBoundingBox(x, y, ctx, selected);
@@ -30182,14 +30192,12 @@ return /******/ (function(modules) { // webpackBootstrap
}, {
key: '_drawRawCircle',
value: function _drawRawCircle(ctx, x, y, selected, hover, size) {
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
-
- ctx.lineWidth = selected ? selectionLineWidth : borderWidth;
- ctx.lineWidth *= this.networkScaleInv;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(x, y, size);
@@ -30202,11 +30210,14 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
}
}, {
@@ -30413,13 +30424,12 @@ return /******/ (function(modules) { // webpackBootstrap
this.left = x - this.width / 2;
this.top = y - this.height / 2;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = this.selected ? selectionLineWidth : borderWidth;
- ctx.lineWidth *= this.networkScaleInv;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.database(x - this.width / 2, y - this.height * 0.5, this.width, this.height);
@@ -30433,11 +30443,14 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
this.updateBoundingBox(x, y, ctx, selected);
@@ -30576,13 +30589,12 @@ return /******/ (function(modules) { // webpackBootstrap
this.left = x - this.width / 2;
this.top = y - this.height / 2;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = selected ? selectionLineWidth : borderWidth;
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx[shape](x, y, this.options.size);
@@ -30595,11 +30607,14 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
if (this.options.label !== undefined) {
@@ -30742,15 +30757,13 @@ return /******/ (function(modules) { // webpackBootstrap
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = selected ? selectionLineWidth : borderWidth;
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
-
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.ellipse(this.left, this.top, this.width, this.height);
@@ -30763,11 +30776,16 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
+
ctx.restore();
this.updateBoundingBox(x, y, ctx, selected);
@@ -30966,17 +30984,15 @@ return /******/ (function(modules) { // webpackBootstrap
this.top = y - this.height / 2;
if (this.options.shapeProperties.useBorderWithImage === true) {
- var borderWidth = this.options.borderWidth;
-
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.beginPath();
// setup the line properties.
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = selected ? selectionLineWidth : borderWidth;
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
// set a fillstyle
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
@@ -30987,11 +31003,14 @@ return /******/ (function(modules) { // webpackBootstrap
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
ctx.closePath();
@@ -40199,7 +40218,7 @@ return /******/ (function(modules) { // webpackBootstrap
// force all edges into static smooth curves. Only applies to edges that do not use the global options for smooth.
this.body.emitter.emit('_forceDisableDynamicCurves', type);
}
- console.log(JSON.stringify(allOptions), JSON.stringify(this.optionsBackup));
+
return allOptions;
}
}, {
@@ -40394,6 +40413,14 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
+ // fallback for cases where there are nodes but no edges
+ for (var _nodeId in this.body.nodes) {
+ if (this.body.nodes.hasOwnProperty(_nodeId)) {
+ if (this.hierarchicalLevels[_nodeId] === undefined) {
+ this.hierarchicalLevels[_nodeId] = 0;
+ }
+ }
+ }
// check the distribution of the nodes per level.
var distribution = this._getDistribution();
@@ -40459,7 +40486,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
}
- return [min, max];
+ return { min: min, max: max };
};
// get the width of all trees
@@ -40849,27 +40876,31 @@ return /******/ (function(modules) { // webpackBootstrap
useMap = false;
}
var level = this.hierarchicalLevels[node.id];
- var index = this.distributionIndex[node.id];
- var position = this._getPositionForHierarchy(node);
- var minSpace = 1e9;
- var maxSpace = 1e9;
- if (index !== 0) {
- var prevNode = this.distributionOrdering[level][index - 1];
- if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
- var prevPos = this._getPositionForHierarchy(prevNode);
- minSpace = position - prevPos;
+ if (level !== undefined) {
+ var index = this.distributionIndex[node.id];
+ var position = this._getPositionForHierarchy(node);
+ var minSpace = 1e9;
+ var maxSpace = 1e9;
+ if (index !== 0) {
+ var prevNode = this.distributionOrdering[level][index - 1];
+ if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
+ var prevPos = this._getPositionForHierarchy(prevNode);
+ minSpace = position - prevPos;
+ }
}
- }
- if (index != this.distributionOrdering[level].length - 1) {
- var nextNode = this.distributionOrdering[level][index + 1];
- if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
- var nextPos = this._getPositionForHierarchy(nextNode);
- maxSpace = Math.min(maxSpace, nextPos - position);
+ if (index != this.distributionOrdering[level].length - 1) {
+ var nextNode = this.distributionOrdering[level][index + 1];
+ if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
+ var nextPos = this._getPositionForHierarchy(nextNode);
+ maxSpace = Math.min(maxSpace, nextPos - position);
+ }
}
- }
- return [minSpace, maxSpace];
+ return [minSpace, maxSpace];
+ } else {
+ return [0, 0];
+ }
}
/**
@@ -41127,14 +41158,18 @@ return /******/ (function(modules) { // webpackBootstrap
// get the minimum level
for (var nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
- minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel);
+ if (this.hierarchicalLevels[nodeId] !== undefined) {
+ minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel);
+ }
}
}
// subtract the minimum from the set so we have a range starting from 0
for (var nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
- this.hierarchicalLevels[nodeId] -= minLevel;
+ if (this.hierarchicalLevels[nodeId] !== undefined) {
+ this.hierarchicalLevels[nodeId] -= minLevel;
+ }
}
}
}
@@ -41183,15 +41218,17 @@ return /******/ (function(modules) { // webpackBootstrap
progress[node.id] = true;
var childNode = undefined;
for (var i = 0; i < node.edges.length; i++) {
- if (node.edges[i].toId === node.id) {
- childNode = node.edges[i].from;
- } else {
- childNode = node.edges[i].to;
- }
+ if (node.edges[i].connected === true) {
+ if (node.edges[i].toId === node.id) {
+ childNode = node.edges[i].from;
+ } else {
+ childNode = node.edges[i].to;
+ }
- if (node.id !== childNode.id) {
- callback(node, childNode, node.edges[i]);
- crawler(childNode);
+ if (node.id !== childNode.id) {
+ callback(node, childNode, node.edges[i]);
+ crawler(childNode);
+ }
}
}
}
@@ -41395,6 +41432,7 @@ return /******/ (function(modules) { // webpackBootstrap
}
}
}
+
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
node.x = position;
} else {
@@ -42132,7 +42170,7 @@ return /******/ (function(modules) { // webpackBootstrap
this.canvas.frame.removeChild(this.editModeDiv);
}
if (this.closeDiv) {
- this.canvas.frame.removeChild(this.manipulationDiv);
+ this.canvas.frame.removeChild(this.closeDiv);
}
// set the references to undefined
diff --git a/docs/data/dataset.html b/docs/data/dataset.html
index 39af677a..c143305c 100644
--- a/docs/data/dataset.html
+++ b/docs/data/dataset.html
@@ -104,7 +104,7 @@
Vis.js comes with a flexible DataSet, which can be used to hold and
manipulate unstructured data and listen for changes in the data.
The DataSet is key/value based. Data items can be added, updated and
- removed from the DatSet, and one can subscribe to changes in the DataSet.
+ removed from the DataSet, and one can subscribe to changes in the DataSet.
The data in the DataSet can be filtered and ordered, and fields (like
dates) can be converted to a specific type. Data can be normalized when
appending it to the DataSet as well.
@@ -1020,4 +1020,4 @@ var positiveBalance = dataset.get({
-
\ No newline at end of file
+
diff --git a/lib/network/modules/LayoutEngine.js b/lib/network/modules/LayoutEngine.js
index 6585483f..8e4fc6b3 100644
--- a/lib/network/modules/LayoutEngine.js
+++ b/lib/network/modules/LayoutEngine.js
@@ -148,7 +148,7 @@ class LayoutEngine {
// force all edges into static smooth curves. Only applies to edges that do not use the global options for smooth.
this.body.emitter.emit('_forceDisableDynamicCurves', type);
}
- console.log(JSON.stringify(allOptions), JSON.stringify(this.optionsBackup));
+
return allOptions;
}
@@ -339,6 +339,15 @@ class LayoutEngine {
}
}
+
+ // fallback for cases where there are nodes but no edges
+ for (let nodeId in this.body.nodes) {
+ if (this.body.nodes.hasOwnProperty(nodeId)) {
+ if (this.hierarchicalLevels[nodeId] === undefined) {
+ this.hierarchicalLevels[nodeId] = 0;
+ }
+ }
+ }
// check the distribution of the nodes per level.
let distribution = this._getDistribution();
@@ -400,7 +409,7 @@ class LayoutEngine {
}
}
}
- return [min, max];
+ return {min:min, max:max};
};
// get the width of all trees
@@ -751,27 +760,32 @@ class LayoutEngine {
useMap = false;
}
let level = this.hierarchicalLevels[node.id];
- let index = this.distributionIndex[node.id];
- let position = this._getPositionForHierarchy(node);
- let minSpace = 1e9;
- let maxSpace = 1e9;
- if (index !== 0) {
- let prevNode = this.distributionOrdering[level][index - 1];
- if ((useMap === true && map[prevNode.id] === undefined) || useMap === false) {
- let prevPos = this._getPositionForHierarchy(prevNode);
- minSpace = position - prevPos;
+ if (level !== undefined) {
+ let index = this.distributionIndex[node.id];
+ let position = this._getPositionForHierarchy(node);
+ let minSpace = 1e9;
+ let maxSpace = 1e9;
+ if (index !== 0) {
+ let prevNode = this.distributionOrdering[level][index - 1];
+ if ((useMap === true && map[prevNode.id] === undefined) || useMap === false) {
+ let prevPos = this._getPositionForHierarchy(prevNode);
+ minSpace = position - prevPos;
+ }
}
- }
- if (index != this.distributionOrdering[level].length - 1) {
- let nextNode = this.distributionOrdering[level][index + 1];
- if ((useMap === true && map[nextNode.id] === undefined) || useMap === false) {
- let nextPos = this._getPositionForHierarchy(nextNode);
- maxSpace = Math.min(maxSpace, nextPos - position);
+ if (index != this.distributionOrdering[level].length - 1) {
+ let nextNode = this.distributionOrdering[level][index + 1];
+ if ((useMap === true && map[nextNode.id] === undefined) || useMap === false) {
+ let nextPos = this._getPositionForHierarchy(nextNode);
+ maxSpace = Math.min(maxSpace, nextPos - position);
+ }
}
- }
- return [minSpace, maxSpace];
+ return [minSpace, maxSpace];
+ }
+ else {
+ return [0, 0];
+ }
}
/**
@@ -1007,14 +1021,18 @@ class LayoutEngine {
// get the minimum level
for (let nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
- minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel);
+ if (this.hierarchicalLevels[nodeId] !== undefined) {
+ minLevel = Math.min(this.hierarchicalLevels[nodeId], minLevel);
+ }
}
}
// subtract the minimum from the set so we have a range starting from 0
for (let nodeId in this.body.nodes) {
if (this.body.nodes.hasOwnProperty(nodeId)) {
- this.hierarchicalLevels[nodeId] -= minLevel;
+ if (this.hierarchicalLevels[nodeId] !== undefined) {
+ this.hierarchicalLevels[nodeId] -= minLevel;
+ }
}
}
}
@@ -1057,12 +1075,18 @@ class LayoutEngine {
progress[node.id] = true;
let childNode;
for (let i = 0; i < node.edges.length; i++) {
- if (node.edges[i].toId === node.id) {childNode = node.edges[i].from;}
- else {childNode = node.edges[i].to;}
+ if (node.edges[i].connected === true) {
+ if (node.edges[i].toId === node.id) {
+ childNode = node.edges[i].from;
+ }
+ else {
+ childNode = node.edges[i].to;
+ }
- if (node.id !== childNode.id) {
- callback(node, childNode, node.edges[i]);
- crawler(childNode);
+ if (node.id !== childNode.id) {
+ callback(node, childNode, node.edges[i]);
+ crawler(childNode);
+ }
}
}
}
@@ -1259,6 +1283,7 @@ class LayoutEngine {
}
}
}
+
if (this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU') {
node.x = position;
}
diff --git a/lib/network/modules/ManipulationSystem.js b/lib/network/modules/ManipulationSystem.js
index 558da3bc..158f6a9a 100644
--- a/lib/network/modules/ManipulationSystem.js
+++ b/lib/network/modules/ManipulationSystem.js
@@ -642,7 +642,7 @@ class ManipulationSystem {
// remove the manipulation divs
if (this.manipulationDiv) {this.canvas.frame.removeChild(this.manipulationDiv);}
if (this.editModeDiv) {this.canvas.frame.removeChild(this.editModeDiv);}
- if (this.closeDiv) {this.canvas.frame.removeChild(this.manipulationDiv);}
+ if (this.closeDiv) {this.canvas.frame.removeChild(this.closeDiv);}
// set the references to undefined
this.manipulationDiv = undefined;
diff --git a/lib/network/modules/components/nodes/shapes/Box.js b/lib/network/modules/components/nodes/shapes/Box.js
index f03b02a8..d2d15740 100644
--- a/lib/network/modules/components/nodes/shapes/Box.js
+++ b/lib/network/modules/components/nodes/shapes/Box.js
@@ -44,11 +44,14 @@ class Box extends NodeBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
this.updateBoundingBox(x,y,ctx,selected);
diff --git a/lib/network/modules/components/nodes/shapes/Database.js b/lib/network/modules/components/nodes/shapes/Database.js
index 3cd1a3c3..dabc02ff 100644
--- a/lib/network/modules/components/nodes/shapes/Database.js
+++ b/lib/network/modules/components/nodes/shapes/Database.js
@@ -23,13 +23,12 @@ class Database extends NodeBase {
this.left = x - this.width / 2;
this.top = y - this.height / 2;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = (this.selected ? selectionLineWidth : borderWidth);
- ctx.lineWidth *= this.networkScaleInv;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.database(x - this.width / 2, y - this.height * 0.5, this.width, this.height);
@@ -43,11 +42,14 @@ class Database extends NodeBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
this.updateBoundingBox(x,y,ctx,selected);
diff --git a/lib/network/modules/components/nodes/shapes/Ellipse.js b/lib/network/modules/components/nodes/shapes/Ellipse.js
index 0265b1fe..b4d0a28a 100644
--- a/lib/network/modules/components/nodes/shapes/Ellipse.js
+++ b/lib/network/modules/components/nodes/shapes/Ellipse.js
@@ -25,15 +25,13 @@ class Ellipse extends NodeBase {
this.left = x - this.width * 0.5;
this.top = y - this.height * 0.5;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
-
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.ellipse(this.left, this.top, this.width, this.height);
@@ -46,11 +44,16 @@ class Ellipse extends NodeBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
+
ctx.restore();
this.updateBoundingBox(x, y, ctx, selected);
diff --git a/lib/network/modules/components/nodes/shapes/Image.js b/lib/network/modules/components/nodes/shapes/Image.js
index 4d812c0f..1a0e8aec 100644
--- a/lib/network/modules/components/nodes/shapes/Image.js
+++ b/lib/network/modules/components/nodes/shapes/Image.js
@@ -18,17 +18,15 @@ class Image extends CircleImageBase {
this.top = y - this.height / 2;
if (this.options.shapeProperties.useBorderWithImage === true) {
- let borderWidth = this.options.borderWidth;
-
- let selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
+ var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.beginPath();
// setup the line properties.
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
// set a fillstyle
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
@@ -42,11 +40,14 @@ class Image extends CircleImageBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
ctx.closePath();
diff --git a/lib/network/modules/components/nodes/util/CircleImageBase.js b/lib/network/modules/components/nodes/util/CircleImageBase.js
index e4d9f803..ab0cf97f 100644
--- a/lib/network/modules/components/nodes/util/CircleImageBase.js
+++ b/lib/network/modules/components/nodes/util/CircleImageBase.js
@@ -66,14 +66,12 @@ class CircleImageBase extends NodeBase {
}
_drawRawCircle(ctx, x, y, selected, hover, size) {
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
-
- ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
- ctx.lineWidth *= this.networkScaleInv;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx.circle(x, y, size);
@@ -86,11 +84,14 @@ class CircleImageBase extends NodeBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
}
diff --git a/lib/network/modules/components/nodes/util/ShapeBase.js b/lib/network/modules/components/nodes/util/ShapeBase.js
index 62901f0c..d9e2cce2 100644
--- a/lib/network/modules/components/nodes/util/ShapeBase.js
+++ b/lib/network/modules/components/nodes/util/ShapeBase.js
@@ -20,13 +20,12 @@ class ShapeBase extends NodeBase {
this.left = x - this.width / 2;
this.top = y - this.height / 2;
- var borderWidth = this.options.borderWidth;
+ var neutralborderWidth = this.options.borderWidth;
var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
+ var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
+ ctx.lineWidth = Math.min(this.width, borderWidth);
ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
- ctx.lineWidth = (selected ? selectionLineWidth : borderWidth);
- ctx.lineWidth /= this.body.view.scale;
- ctx.lineWidth = Math.min(this.width, ctx.lineWidth);
ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
ctx[shape](x, y, this.options.size);
@@ -39,11 +38,14 @@ class ShapeBase extends NodeBase {
//draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
ctx.save();
- this.enableBorderDashes(ctx);
- //draw the border
- ctx.stroke();
- //disable dashed border for other elements
- this.disableBorderDashes(ctx);
+ // if borders are zero width, they will be drawn with width 1 by default. This prevents that
+ if (borderWidth > 0) {
+ this.enableBorderDashes(ctx);
+ //draw the border
+ ctx.stroke();
+ //disable dashed border for other elements
+ this.disableBorderDashes(ctx);
+ }
ctx.restore();
if (this.options.label !== undefined) {