From 944511f4c78b988f5ee7702040acad019b6f23ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Martins?= Date: Tue, 14 Jun 2016 02:54:40 +0100 Subject: [PATCH 01/43] Fixed getPoint for same node edges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Martins --- .../modules/components/edges/BezierEdgeDynamic.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/network/modules/components/edges/BezierEdgeDynamic.js b/lib/network/modules/components/edges/BezierEdgeDynamic.js index 0108d50a..c35d641a 100644 --- a/lib/network/modules/components/edges/BezierEdgeDynamic.js +++ b/lib/network/modules/components/edges/BezierEdgeDynamic.js @@ -133,8 +133,16 @@ class BezierEdgeDynamic extends BezierEdgeBase { */ getPoint(percentage, viaNode = this.via) { let t = percentage; - let x = Math.pow(1 - t, 2) * this.fromPoint.x + (2 * t * (1 - t)) * viaNode.x + Math.pow(t, 2) * this.toPoint.x; - let y = Math.pow(1 - t, 2) * this.fromPoint.y + (2 * t * (1 - t)) * viaNode.y + Math.pow(t, 2) * this.toPoint.y; + let x, y; + if (this.from === this.to){ + let [cx,cy,cr] = this._getCircleData(this.from) + let a = 2 * Math.PI * (1 - t); + x = cx + cr * Math.sin(a); + y = cy + cr - cr * (1 - Math.cos(a)); + } else { + x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x; + y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y; + } return {x: x, y: y}; } @@ -151,4 +159,4 @@ class BezierEdgeDynamic extends BezierEdgeBase { } -export default BezierEdgeDynamic; \ No newline at end of file +export default BezierEdgeDynamic; From ff3948f85c67985be8af39dc9ace68674386f25d Mon Sep 17 00:00:00 2001 From: Greg Kubisa Date: Tue, 13 Sep 2016 15:28:34 +0100 Subject: [PATCH 02/43] Use requestAnimationFrame to throttle redraws --- docs/timeline/index.html | 25 +++++++++---------------- index-timeline-graph2d.js | 2 +- lib/timeline/Core.js | 7 +++---- lib/timeline/Timeline.js | 5 ++--- lib/timeline/optionsGraph2d.js | 2 -- lib/timeline/optionsTimeline.js | 4 +--- lib/util.js | 27 +++++++++------------------ 7 files changed, 25 insertions(+), 47 deletions(-) diff --git a/docs/timeline/index.html b/docs/timeline/index.html index f0b4d742..f8a71fc4 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -31,13 +31,13 @@ - + - + - + @@ -213,7 +213,7 @@ or a DataView (offering 1 way data binding). Items are regular objects and can contain the properties start, end (optional), content, - group (optional), className (optional), + group (optional), className (optional), editable (optional), and style (optional).

@@ -624,7 +624,7 @@ function (option, path) { If no order properties are provided, the order will be undetermined. - + groupOrderSwap Function @@ -787,7 +787,7 @@ function (option, path) { Only applicable when option selectable is true. - + multiselectPerGroup boolean @@ -805,7 +805,7 @@ function (option, path) { Callback function triggered when an item is about to be added: when the user double taps an empty space in the Timeline. See section Editing Items for more information. Only applicable when both options selectable and editable.add are set true. - + onAddGroup function @@ -829,7 +829,7 @@ function (option, path) { Callback function triggered when an item has been moved: after the user has dragged the item to an other position. See section Editing Items for more information. Only applicable when both options selectable and editable.updateTime or editable.updateGroup are set true. - + onMoveGroup function @@ -853,7 +853,7 @@ function (option, path) { Callback function triggered when an item is about to be removed: when the user tapped the delete button on the top right of a selected item. See section Editing Items for more information. Only applicable when both options selectable and editable.remove are set true. - + onRemoveGroup function @@ -967,13 +967,6 @@ function (option, path) { A template function used to generate the contents of the items. The function is called by the Timeline with an items data as argument, and must return HTML code as result. When the option template is specified, the items do not need to have a field content. See section Templates for a detailed explanation. - - throttleRedraw - number - 0 - Limit the maximum number of redraws to once every x milliseconds. For example setting throttleRedraw to `100` milliseconds will limit the number of redraws to 10 times per second. - - timeAxis Object diff --git a/index-timeline-graph2d.js b/index-timeline-graph2d.js index 50426671..da9e5173 100644 --- a/index-timeline-graph2d.js +++ b/index-timeline-graph2d.js @@ -44,4 +44,4 @@ exports.timeline = { // bundled external libraries exports.moment = require('./lib/module/moment'); exports.Hammer = require('./lib/module/hammer'); -exports.keycharm = require('keycharm'); \ No newline at end of file +exports.keycharm = require('keycharm'); diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index cd53472a..cca32f9c 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -222,8 +222,7 @@ Core.prototype.setOptions = function (options) { var fields = [ 'width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'clickToUse', 'dataAttributes', 'hiddenDates', - 'locale', 'locales', 'moment', 'rtl', - 'throttleRedraw' + 'locale', 'locales', 'moment', 'rtl' ]; util.selectiveExtend(fields, this.options, options); @@ -233,7 +232,7 @@ Core.prototype.setOptions = function (options) { this.dom.leftContainer = this.dom.rightContainer; this.dom.rightContainer = contentContainer; this.dom.container.style.direction = "rtl"; - this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical-rtl'; } + this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical-rtl'; } this.options.orientation = {item:undefined,axis:undefined}; if ('orientation' in options) { @@ -330,7 +329,7 @@ Core.prototype.setOptions = function (options) { // override redraw with a throttled version if (!this._origRedraw) { this._origRedraw = this._redraw.bind(this); - this._redraw = util.throttle(this._origRedraw, this.options.throttleRedraw); + this._redraw = util.throttle(this._origRedraw); } else { // Not the initial run: redraw everything this._redraw(); diff --git a/lib/timeline/Timeline.js b/lib/timeline/Timeline.js index 6d4ef175..941b2dc5 100644 --- a/lib/timeline/Timeline.js +++ b/lib/timeline/Timeline.js @@ -47,7 +47,6 @@ function Timeline (container, items, groups, options) { end: null, autoResize: true, - throttleRedraw: 0, // ms orientation: { axis: 'bottom', // axis orientation: 'bottom', 'top', or 'both' @@ -426,7 +425,7 @@ Timeline.prototype.getItemRange = function () { var start = getStart(item); var end = getEnd(item); - + if (this.options.rtl) { var startSide = start - (item.getWidthRight() + 10) * factor; var endSide = end + (item.getWidthLeft() + 10) * factor; @@ -434,7 +433,7 @@ Timeline.prototype.getItemRange = function () { var startSide = start - (item.getWidthLeft() + 10) * factor; var endSide = end + (item.getWidthRight() + 10) * factor; } - + if (startSide < min) { min = startSide; diff --git a/lib/timeline/optionsGraph2d.js b/lib/timeline/optionsGraph2d.js index fb8e0455..30b27b75 100644 --- a/lib/timeline/optionsGraph2d.js +++ b/lib/timeline/optionsGraph2d.js @@ -100,7 +100,6 @@ let allOptions = { }, autoResize: {boolean}, - throttleRedraw: {number}, clickToUse: {boolean}, end: {number, date, string, moment}, format: { @@ -225,7 +224,6 @@ let configureOptions = { }, autoResize: true, - throttleRedraw: [10, 0, 1000, 10], clickToUse: false, end: '', format: { diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index 0069a3db..fc4330fe 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -27,7 +27,6 @@ let allOptions = { align: {string}, rtl: {boolean, 'undefined': 'undefined'}, autoResize: {boolean}, - throttleRedraw: {number}, clickToUse: {boolean}, dataAttributes: {string, array}, editable: { @@ -145,7 +144,6 @@ let configureOptions = { align: ['center', 'left', 'right'], direction: false, autoResize: true, - throttleRedraw: [10, 0, 1000, 10], clickToUse: false, // dataAttributes: ['all'], // FIXME: can be 'all' or string[] editable: { @@ -229,4 +227,4 @@ let configureOptions = { } }; -export {allOptions, configureOptions}; \ No newline at end of file +export {allOptions, configureOptions}; diff --git a/lib/util.js b/lib/util.js index ce41023c..15eba4cb 100644 --- a/lib/util.js +++ b/lib/util.js @@ -702,29 +702,20 @@ exports.updateProperty = function (object, key, value) { }; /** - * Throttle the given function to be only executed once every `wait` milliseconds + * Throttle the given function to be only executed once per animation frame * @param {function} fn - * @param {number} wait Time in milliseconds * @returns {function} Returns the throttled function */ -exports.throttle = function (fn, wait) { - var timeout = null; - var needExecution = false; +exports.throttle = function (fn) { + var scheduled = false; return function throttled () { - if (!timeout) { - needExecution = false; - fn(); - - timeout = setTimeout(function() { - timeout = null; - if (needExecution) { - throttled(); - } - }, wait) - } - else { - needExecution = true; + if (!scheduled) { + scheduled = true; + requestAnimationFrame(function () { + scheduled = false; + fn(); + }); } } }; From 217299ed350e4ae4c3d4a43420fc491aa8e9f8c6 Mon Sep 17 00:00:00 2001 From: Tom Manderson Date: Mon, 17 Oct 2016 18:15:26 +1000 Subject: [PATCH 03/43] Add the source data to Point3d objects in Graph3D (#1884) * Add the source data to Point3d objects in Graph3D; This allows more complex tooltips, using information sent from the server + the source object * Update PR as requested * Convert tabs to spaces; Vim config was off, edited in sublime instead --- docs/graph3d/index.html | 3 ++- examples/graph3d/11_tooltips.html | 14 ++++++++++---- lib/graph3d/Graph3d.js | 5 +++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/graph3d/index.html b/docs/graph3d/index.html index 16467484..429e2a98 100644 --- a/docs/graph3d/index.html +++ b/docs/graph3d/index.html @@ -474,7 +474,8 @@ var options = { The contents of the tooltip can be customized by providing a callback function as tooltip. In this case the function is called with an object containing parameters x, - y, and z argument, + y, z, and data + (the source JS object for the point) as an argument, and must return a string which may contain HTML. diff --git a/examples/graph3d/11_tooltips.html b/examples/graph3d/11_tooltips.html index 508e7e0a..39af19aa 100644 --- a/examples/graph3d/11_tooltips.html +++ b/examples/graph3d/11_tooltips.html @@ -24,6 +24,11 @@ // Create and populate a data table. data = new vis.DataSet(); + var extra_content = [ + 'Arbitrary information', + 'You can access data from the point source object', + 'Tooltip example content', + ]; // create some nice looking data with sin/cos var steps = 5; // number of datapoints will be steps*steps @@ -34,10 +39,10 @@ var z = custom(x,y); if (withValue) { var value = (y - x); - data.add({x:x, y:y, z: z, style:value}); + data.add({x:x, y:y, z: z, style:value, extra: extra_content[(x*y) % extra_content.length]}); } else { - data.add({x:x, y:y, z: z}); + data.add({x:x, y:y, z: z, extra: extra_content[(x*y) % extra_content.length]}); } } } @@ -55,8 +60,9 @@ // Option tooltip can be true, false, or a function returning a string with HTML contents //tooltip: true, tooltip: function (point) { - // parameter point contains properties x, y, z - return 'value: ' + point.z + ''; + // parameter point contains properties x, y, z, and data + // data is the original object passed to the point constructor + return 'value: ' + point.z + '
' + point.data.extra; }, keepAspectRatio: true, diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index f2c17507..01fe7445 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1,5 +1,4 @@ -var Emitter = require('emitter-component'); -var DataSet = require('../DataSet'); +var Emitter = require('emitter-component'); var DataSet = require('../DataSet'); var DataView = require('../DataView'); var util = require('../util'); var Point3d = require('./Point3d'); @@ -561,6 +560,7 @@ Graph3d.prototype._getDataPoints = function (data) { point3d.x = x; point3d.y = y; point3d.z = z; + point3d.data = data[i]; obj = {}; obj.point = point3d; @@ -594,6 +594,7 @@ Graph3d.prototype._getDataPoints = function (data) { point.x = data[i][this.colX] || 0; point.y = data[i][this.colY] || 0; point.z = data[i][this.colZ] || 0; + point.data = data[i]; if (this.colValue !== undefined) { point.value = data[i][this.colValue] || 0; From f95375b020972f97a3590babaaa1873cda0cd59f Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Fri, 15 Jul 2016 15:03:51 +0200 Subject: [PATCH 04/43] moved some dependencies for production --- package.json | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3b5d25ba..6d82f185 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,13 @@ "watch": "gulp watch", "watch-dev": "gulp watch --bundle" }, - "dependencies": {}, + "dependencies": { + "emitter-component": "^1.1.1", + "moment": "^2.12.0", + "propagating-hammerjs": "^1.4.6", + "hammerjs": "^2.0.6", + "keycharm": "^0.2.0" + }, "devDependencies": { "async": "^2.0.0-rc.2", "babel-core": "^6.6.5", @@ -36,18 +42,13 @@ "babel-preset-es2015": "^6.6.0", "babelify": "^7.2.0", "clean-css": "^3.4.10", - "emitter-component": "^1.1.1", "gulp": "^3.9.1", "gulp-clean-css": "^2.0.11", "gulp-concat": "^2.6.0", "gulp-rename": "^1.2.2", "gulp-util": "^3.0.7", - "hammerjs": "^2.0.6", - "keycharm": "^0.2.0", "merge-stream": "^1.0.0", - "mocha": "^2.5.3", - "moment": "^2.12.0", - "propagating-hammerjs": "^1.4.6", + "mocha": "^2.4.5", "rimraf": "^2.5.2", "uglify-js": "^2.6.2", "uuid": "^2.0.1", From 12e2fa437d9240dc9915669ed30931b5d98964eb Mon Sep 17 00:00:00 2001 From: yotamberk Date: Mon, 17 Oct 2016 11:53:47 +0300 Subject: [PATCH 05/43] Custom function label - fixes #1098 (#2145) * Hide vertically hidden ranged items in groups that are not visible * Add custom function format for time labels * fix misspell * remove spaces * remove backspace * add backspaces * Add docs and examples * Fix docs --- docs/timeline/index.html | 10 +- .../timeline/other/functionLabelFormats.html | 141 ++++++++++++++++++ lib/timeline/TimeStep.js | 8 + lib/timeline/component/Group.js | 4 +- lib/timeline/optionsTimeline.js | 4 +- 5 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 examples/timeline/other/functionLabelFormats.html diff --git a/docs/timeline/index.html b/docs/timeline/index.html index b9182900..70f747be 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -557,7 +557,7 @@ function (option, path) { format - Object + Object or Function none Apply custom date formatting of the labels on the time axis. The default value of format is: @@ -583,8 +583,16 @@ function (option, path) { year: '' } } + For values which not provided in the customized options.format, the default values will be used. All available formatting syntax is described in the docs of moment.js. +
+ You can also use a function format for each label. The function accepts as arguments the date, scale and step in that order, and expects to return a string for the label. + +
function format({
+  minorLabels: Function(date: Date, scale: Number, step: Number),
+  majorLabels: Function(date: Date, scale: Number, step: Number)
+}
diff --git a/examples/timeline/other/functionLabelFormats.html b/examples/timeline/other/functionLabelFormats.html new file mode 100644 index 00000000..9de9023b --- /dev/null +++ b/examples/timeline/other/functionLabelFormats.html @@ -0,0 +1,141 @@ + + + + Timeline | Custom function label format example + + + + + + + + + + + +

+ This example demonstrate using custom function label formats. +

+
+ + + + \ No newline at end of file diff --git a/lib/timeline/TimeStep.js b/lib/timeline/TimeStep.js index c5a9bfc2..dc3991ed 100644 --- a/lib/timeline/TimeStep.js +++ b/lib/timeline/TimeStep.js @@ -532,6 +532,10 @@ TimeStep.prototype.getLabelMinor = function(date) { date = this.current; } + if (typeof(this.format.minorLabels) === "function") { + return this.format.minorLabels(date, this.scale, this.step); + } + var format = this.format.minorLabels[this.scale]; return (format && format.length > 0) ? this.moment(date).format(format) : ''; }; @@ -546,6 +550,10 @@ TimeStep.prototype.getLabelMajor = function(date) { if (date == undefined) { date = this.current; } + + if (typeof(this.format.majorLabels) === "function") { + return this.format.majorLabels(date, this.scale, this.step); + } var format = this.format.majorLabels[this.scale]; return (format && format.length > 0) ? this.moment(date).format(format) : ''; diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 512fac58..3d0d0e82 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -180,6 +180,7 @@ Group.prototype.redraw = function(range, margin, restack) { // recalculate the height of the subgroups this._calculateSubGroupHeights(); + this.isVisible = this._isGroupVisible(range, margin); // reposition visible items vertically @@ -220,7 +221,7 @@ Group.prototype.redraw = function(range, margin, restack) { stack.nostack(this.visibleItems, margin, this.subgroups); } } - + if (!this.isVisible && this.height) { return resized = false; } @@ -275,7 +276,6 @@ Group.prototype._calculateSubGroupHeights = function () { * check if group is visible * @private */ - Group.prototype._isGroupVisible = function (range, margin) { var isVisible = (this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis) diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index fc4330fe..a20d27f4 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -47,7 +47,7 @@ let allOptions = { day: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, - __type__: {object} + __type__: {object, 'function': 'function'} }, majorLabels: { millisecond: {string,'undefined': 'undefined'}, @@ -58,7 +58,7 @@ let allOptions = { day: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, - __type__: {object} + __type__: {object, 'function': 'function'} }, __type__: {object} }, From ea859d4c79fed82a426affa2dcc7cf95821e1614 Mon Sep 17 00:00:00 2001 From: Andrew Speed Date: Mon, 17 Oct 2016 11:54:02 +0100 Subject: [PATCH 06/43] Add example to export to JSON and import it again. (#2152) Networks are exported as a JSON array containing an array of objects representing each node in the network. Each node contains an Id, it's x and y coordinates and the nodes it is connected to. Import converts the JSON to a vis DataSet and then regenerates the network using each node's attributes, inserting it in the same coordinates and with the same number of connections as before. fixes #2073 --- examples/network/other/saveAndLoad.html | 177 ++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 examples/network/other/saveAndLoad.html diff --git a/examples/network/other/saveAndLoad.html b/examples/network/other/saveAndLoad.html new file mode 100644 index 00000000..08165c85 --- /dev/null +++ b/examples/network/other/saveAndLoad.html @@ -0,0 +1,177 @@ + + + + + + Network | Saving and loading networks + + + + + + + + + + + +

+ In this example, the network data can be exported to JSON and imported back into the network. + + Try this out by exporting the network to JSON, clearing the network and then importing it again. The nodes will all appear in the same position as they were before the network was destroyed. +

+ +
+ +
+ + + + +
+ + + + \ No newline at end of file From 439aa79a687e680d97f36260d11d356439a1b8fb Mon Sep 17 00:00:00 2001 From: yotamberk Date: Mon, 17 Oct 2016 14:06:15 +0300 Subject: [PATCH 07/43] Expose the item/group element in option.template and option.groupTemplate (#2153) * Hide vertically hidden ranged items in groups that are not visible * Add element to templates options * Fix comment typo * Add documentation for react mounting --- docs/timeline/index.html | 15 +++++++++++++-- lib/timeline/component/Group.js | 2 +- lib/timeline/component/item/Item.js | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/timeline/index.html b/docs/timeline/index.html index 70f747be..f32ac2a2 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -648,7 +648,7 @@ function (option, path) { groupTemplate function none - A template function used to generate the contents of the groups. The function is called by the Timeline with a groups data as argument, and must return HTML code as result. When the option groupTemplate is specified, the groups do not need to have a field content. See section Templates for a detailed explanation. + A template function used to generate the contents of the groups. The function is called by the Timeline with a groups data as the first argument and the group element as the second, and must return HTML code as result. When the option groupTemplate is specified, the groups do not need to have a field content. See section Templates for a detailed explanation. @@ -978,7 +978,7 @@ function (option, path) { template function none - A template function used to generate the contents of the items. The function is called by the Timeline with an items data as argument, and must return HTML code as result. When the option template is specified, the items do not need to have a field content. See section Templates for a detailed explanation. + A template function used to generate the contents of the items. The function is called by the Timeline with an items data as the first argument and the item element as the second, and must return HTML code as result. When the option template is specified, the items do not need to have a field content. See section Templates for a detailed explanation. @@ -1630,6 +1630,17 @@ var template = Handlebars.compile(source); }; +

React templates

+ +You can use a React component for the templates by rendering them to the templates' element directly: + +
+  template: function (item, element) {
+    return ReactDOM.render(<b>{item.content}</b>, element);
+  },
+
+ +

Multiple templates

In order to support multiple templates, the template handler can be extended to switch between different templates, depending on a specific item property: diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 3d0d0e82..3302c67e 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -88,7 +88,7 @@ Group.prototype.setData = function(data) { // update contents var content; if (this.itemSet.options && this.itemSet.options.groupTemplate) { - content = this.itemSet.options.groupTemplate(data); + content = this.itemSet.options.groupTemplate(data, this.dom.inner); } else { content = data && data.content; diff --git a/lib/timeline/component/item/Item.js b/lib/timeline/component/item/Item.js index ea5c7cbb..743e5944 100644 --- a/lib/timeline/component/item/Item.js +++ b/lib/timeline/component/item/Item.js @@ -190,7 +190,7 @@ Item.prototype._updateContents = function (element) { var content; if (this.options.template) { var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset - content = this.options.template(itemData); + content = this.options.template(itemData, element); } else { content = this.data.content; From dc2c233b55923a1057293c43893ea972faaed6ea Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Sun, 4 Sep 2016 14:19:35 +0200 Subject: [PATCH 08/43] added arrow-type 'circle'; fixes #1993 --- lib/network/modules/EdgesHandler.js | 8 ++++---- lib/network/modules/PhysicsEngine.js | 10 +++++----- .../modules/components/edges/util/EdgeBase.js | 17 +++++++++++++---- lib/network/options.js | 12 ++++++------ lib/network/shapes.js | 14 ++++++++++++-- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/lib/network/modules/EdgesHandler.js b/lib/network/modules/EdgesHandler.js index 4be26d95..e57e86e5 100644 --- a/lib/network/modules/EdgesHandler.js +++ b/lib/network/modules/EdgesHandler.js @@ -23,9 +23,9 @@ class EdgesHandler { this.options = {}; this.defaultOptions = { arrows: { - to: {enabled: false, scaleFactor:1}, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1} - middle: {enabled: false, scaleFactor:1}, - from: {enabled: false, scaleFactor:1} + to: {enabled: false, scaleFactor:1, type: 'arrow'}, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1} + middle: {enabled: false, scaleFactor:1, type: 'arrow'}, + from: {enabled: false, scaleFactor:1, type: 'arrow'} }, arrowStrikethrough: true, color: { @@ -388,4 +388,4 @@ class EdgesHandler { } -export default EdgesHandler; \ No newline at end of file +export default EdgesHandler; diff --git a/lib/network/modules/PhysicsEngine.js b/lib/network/modules/PhysicsEngine.js index 7d538906..3555c2ff 100644 --- a/lib/network/modules/PhysicsEngine.js +++ b/lib/network/modules/PhysicsEngine.js @@ -628,7 +628,7 @@ class PhysicsEngine { this._freezeNodes(); } this.stabilizationIterations = 0; - + setTimeout(() => this._stabilizationBatch(),0); } @@ -649,7 +649,7 @@ class PhysicsEngine { this.physicsTick(); count++; } - + if (this.stabilized === false && this.stabilizationIterations < this.targetIterations) { this.body.emitter.emit('stabilizationProgress', {iterations: this.stabilizationIterations, total: this.targetIterations}); setTimeout(this._stabilizationBatch.bind(this),0); @@ -710,11 +710,11 @@ class PhysicsEngine { let angle = Math.atan2(force.y, force.x); ctx.fillStyle = color; - ctx.arrow(node.x + factor*force.x + Math.cos(angle)*arrowSize, node.y + factor*force.y+Math.sin(angle)*arrowSize, angle, arrowSize); + ctx.arrowEndpoint(node.x + factor*force.x + Math.cos(angle)*arrowSize, node.y + factor*force.y+Math.sin(angle)*arrowSize, angle, arrowSize); ctx.fill(); } } - + } -export default PhysicsEngine; \ No newline at end of file +export default PhysicsEngine; diff --git a/lib/network/modules/components/edges/util/EdgeBase.js b/lib/network/modules/components/edges/util/EdgeBase.js index 659313a1..1371ab4e 100644 --- a/lib/network/modules/components/edges/util/EdgeBase.js +++ b/lib/network/modules/components/edges/util/EdgeBase.js @@ -412,6 +412,7 @@ class EdgeBase { let node2; let guideOffset; let scaleFactor; + let type; let lineWidth = this.getLineWidth(selected, hover); if (position === 'from') { @@ -419,17 +420,20 @@ class EdgeBase { node2 = this.to; guideOffset = 0.1; scaleFactor = this.options.arrows.from.scaleFactor; + type = this.options.arrows.from.type; } else if (position === 'to') { node1 = this.to; node2 = this.from; guideOffset = -0.1; scaleFactor = this.options.arrows.to.scaleFactor; + type = this.options.arrows.to.type; } else { node1 = this.to; node2 = this.from; scaleFactor = this.options.arrows.middle.scaleFactor; + type = this.options.arrows.middle.type; } // if not connected to itself @@ -475,7 +479,7 @@ class EdgeBase { var yi = arrowPoint.y - length * 0.9 * Math.sin(angle); let arrowCore = {x: xi, y: yi}; - return {point: arrowPoint, core: arrowCore, angle: angle, length: length}; + return {point: arrowPoint, core: arrowCore, angle: angle, length: length, type: type}; } /** @@ -491,8 +495,13 @@ class EdgeBase { ctx.fillStyle = ctx.strokeStyle; ctx.lineWidth = this.getLineWidth(selected, hover); - // draw arrow at the end of the line - ctx.arrow(arrowData.point.x, arrowData.point.y, arrowData.angle, arrowData.length); + if (arrowData.type && arrowData.type.toLowerCase() === 'circle') { + // draw circle at the end of the line + ctx.circleEndpoint(arrowData.point.x, arrowData.point.y, arrowData.angle, arrowData.length); + } else { + // draw arrow at the end of the line + ctx.arrowEndpoint(arrowData.point.x, arrowData.point.y, arrowData.angle, arrowData.length); + } // draw shadow if enabled this.enableShadow(ctx); @@ -521,4 +530,4 @@ class EdgeBase { } } -export default EdgeBase; \ No newline at end of file +export default EdgeBase; diff --git a/lib/network/options.js b/lib/network/options.js index 9c0ff2b8..6238182a 100644 --- a/lib/network/options.js +++ b/lib/network/options.js @@ -24,9 +24,9 @@ let allOptions = { }, edges: { arrows: { - to: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } }, - middle: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } }, - from: { enabled: { boolean }, scaleFactor: { number }, __type__: { object, boolean } }, + to: { enabled: { boolean }, scaleFactor: { number }, type: { string: ['arrow', 'circle'] }, __type__: { object, boolean } }, + middle: { enabled: { boolean }, scaleFactor: { number }, type: { string: ['arrow', 'circle'] }, __type__: { object, boolean } }, + from: { enabled: { boolean }, scaleFactor: { number }, type: { string: ['arrow', 'circle'] }, __type__: { object, boolean } }, __type__: { string: ['from', 'to', 'middle'], object } }, arrowStrikethrough: { boolean }, @@ -371,9 +371,9 @@ let configureOptions = { }, edges: { arrows: { - to: { enabled: false, scaleFactor: [1, 0, 3, 0.05] }, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1} - middle: { enabled: false, scaleFactor: [1, 0, 3, 0.05] }, - from: { enabled: false, scaleFactor: [1, 0, 3, 0.05] } + to: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' }, + middle: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' }, + from: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' } }, arrowStrikethrough: true, color: { diff --git a/lib/network/shapes.js b/lib/network/shapes.js index f2232bfc..ddc26ea0 100644 --- a/lib/network/shapes.js +++ b/lib/network/shapes.js @@ -206,9 +206,9 @@ if (typeof CanvasRenderingContext2D !== 'undefined') { /** - * Draw an arrow point (no line) + * Draw an arrow an the end of an line with the given angle. */ - CanvasRenderingContext2D.prototype.arrow = function (x, y, angle, length) { + CanvasRenderingContext2D.prototype.arrowEndpoint = function (x, y, angle, length) { // tail var xt = x - length * Math.cos(angle); var yt = y - length * Math.sin(angle); @@ -233,6 +233,16 @@ if (typeof CanvasRenderingContext2D !== 'undefined') { this.closePath(); }; + /** + * Draw an circle an the end of an line with the given angle. + */ + CanvasRenderingContext2D.prototype.circleEndpoint = function (x, y, angle, length) { + var radius = length * 0.4; + var xc = x - radius * Math.cos(angle); + var yc = y - radius * Math.sin(angle); + this.circle(xc, yc, radius); + }; + /** * Sets up the dashedLine functionality for drawing * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas From 0970cf69adf02bd4587dfaba5935ea37c8a1bb95 Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Sun, 4 Sep 2016 14:21:36 +0200 Subject: [PATCH 09/43] added arrow-type example; #1993 --- examples/network/edgeStyles/arrowTypes.html | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 examples/network/edgeStyles/arrowTypes.html diff --git a/examples/network/edgeStyles/arrowTypes.html b/examples/network/edgeStyles/arrowTypes.html new file mode 100644 index 00000000..25cf63bf --- /dev/null +++ b/examples/network/edgeStyles/arrowTypes.html @@ -0,0 +1,55 @@ + + + + Network | Basic usage + + + + + + + + +

+ There two type of liner endings. The classical "arrow" (default) and "circle". +

+ +
+ + + + + + From 37c595e906b5e4a85b850de0be48312ff72b17f6 Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Sun, 4 Sep 2016 14:27:28 +0200 Subject: [PATCH 10/43] added arrow-type docs; #1993 --- docs/network/edges.html | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/network/edges.html b/docs/network/edges.html index 42c132ac..423f9a45 100644 --- a/docs/network/edges.html +++ b/docs/network/edges.html @@ -115,9 +115,9 @@ var options = { edges:{ arrows: { - to: {enabled: false, scaleFactor:1}, - middle: {enabled: false, scaleFactor:1}, - from: {enabled: false, scaleFactor:1} + to: {enabled: false, scaleFactor:1, type:'arrow'}, + middle: {enabled: false, scaleFactor:1, type:'arrow'}, + from: {enabled: false, scaleFactor:1, type:'arrow'} }, arrowStrikethrough: true, color: { @@ -243,6 +243,12 @@ network.setOptions(options); 1 The scale factor allows you to change the size of the arrowhead. + + arrows.to.type + String + arrow + The type of endpoint. Default is arrow. Also possible is circle. + arrows.middle Object or Boolean @@ -703,4 +709,4 @@ var options: { - \ No newline at end of file + From d2aa7b01c2e689556a821756ebf8c857a036216a Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Mon, 17 Oct 2016 13:10:05 +0200 Subject: [PATCH 11/43] fixed typo --- lib/network/shapes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/network/shapes.js b/lib/network/shapes.js index ddc26ea0..9346f482 100644 --- a/lib/network/shapes.js +++ b/lib/network/shapes.js @@ -206,7 +206,7 @@ if (typeof CanvasRenderingContext2D !== 'undefined') { /** - * Draw an arrow an the end of an line with the given angle. + * Draw an arrow at the end of a line with the given angle. */ CanvasRenderingContext2D.prototype.arrowEndpoint = function (x, y, angle, length) { // tail From 932dfb1754e0e85a3d73c5b46a11eecce02acf37 Mon Sep 17 00:00:00 2001 From: yotamberk Date: Mon, 17 Oct 2016 15:32:03 +0300 Subject: [PATCH 12/43] Fix Vertical visibility for all item types (#2143) * Hide vertically hidden ranged items in groups that are not visible * Fix misspelling * Fix examples that do not contain groups * Add example for vertical hidden ranged items * Fix indent format in RangeItem * Fix example * Fix other examples after addition of vertical hiding range items in groups * Add case of zero margin axis * Fix commented out lines in examples * Fix vertical visibility bug --- .../timeline/groups/verticalItemsHide.html | 4 ++++ lib/timeline/component/Group.js | 24 +++++++------------ lib/timeline/component/item/BackgroundItem.js | 2 +- lib/timeline/component/item/BoxItem.js | 19 ++++++++++++--- lib/timeline/component/item/Item.js | 1 - lib/timeline/component/item/PointItem.js | 7 +++--- lib/timeline/component/item/RangeItem.js | 10 ++------ 7 files changed, 36 insertions(+), 31 deletions(-) diff --git a/examples/timeline/groups/verticalItemsHide.html b/examples/timeline/groups/verticalItemsHide.html index 493a6ac7..1f38fffe 100644 --- a/examples/timeline/groups/verticalItemsHide.html +++ b/examples/timeline/groups/verticalItemsHide.html @@ -72,6 +72,7 @@ // create items var items = new vis.DataSet(); + var types = [ 'box', 'point', 'range', 'background'] var order = 1; var truck = 1; for (var j = 0; j < 25; j++) { @@ -83,11 +84,14 @@ date.setHours(date.getHours() + 2 + Math.floor(Math.random()*4)); var end = new Date(date); + var type = types[Math.floor(4 * Math.random())] + items.add({ id: order, group: truck, start: start, end: end, + type: type, content: 'Order ' + order }); diff --git a/lib/timeline/component/Group.js b/lib/timeline/component/Group.js index 3302c67e..f522fd82 100644 --- a/lib/timeline/component/Group.js +++ b/lib/timeline/component/Group.js @@ -180,9 +180,16 @@ Group.prototype.redraw = function(range, margin, restack) { // recalculate the height of the subgroups this._calculateSubGroupHeights(); - + this.isVisible = this._isGroupVisible(range, margin); + // calculate actual size and position + var foreground = this.dom.foreground; + this.top = foreground.offsetTop; + this.right = foreground.offsetLeft; + this.width = foreground.offsetWidth; + + this.isVisible = this._isGroupVisible(range, margin); // reposition visible items vertically if (typeof this.itemSet.options.order === 'function') { // a custom order function @@ -556,20 +563,7 @@ Group.prototype._updateVisibleItems = function(orderedItems, oldVisibleItems, ra // reposition item horizontally item.repositionX(); } - - // debug - //console.log("new line") - //if (this.groupId == null) { - // for (i = 0; i < orderedItems.byStart.length; i++) { - // item = orderedItems.byStart[i].data; - // console.log('start',i,initialPosByStart, item.start.valueOf(), item.content, item.start >= lowerBound && item.start <= upperBound,i == initialPosByStart ? "<------------------- HEREEEE" : "") - // } - // for (i = 0; i < orderedItems.byEnd.length; i++) { - // item = orderedItems.byEnd[i].data; - // console.log('rangeEnd',i,initialPosByEnd, item.end.valueOf(), item.content, item.end >= range.start && item.end <= range.end,i == initialPosByEnd ? "<------------------- HEREEEE" : "") - // } - //} - + return visibleItems; }; diff --git a/lib/timeline/component/item/BackgroundItem.js b/lib/timeline/component/item/BackgroundItem.js index cdebc4ed..44048527 100644 --- a/lib/timeline/component/item/BackgroundItem.js +++ b/lib/timeline/component/item/BackgroundItem.js @@ -47,7 +47,7 @@ BackgroundItem.prototype.stack = false; */ BackgroundItem.prototype.isVisible = function(range) { // determine visibility - return (this.data.start < range.end) && (this.data.end > range.start); + return (this.data.start < range.end) && (this.data.end > range.start); }; /** diff --git a/lib/timeline/component/item/BoxItem.js b/lib/timeline/component/item/BoxItem.js index 4a6d5e9e..f77652bf 100644 --- a/lib/timeline/component/item/BoxItem.js +++ b/lib/timeline/component/item/BoxItem.js @@ -42,9 +42,22 @@ BoxItem.prototype = new Item (null, null, null); */ BoxItem.prototype.isVisible = function(range) { // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + var isVisible; + var align = this.options.align; + var msPerPixel = (range.end - range.start) / range.body.dom.center.clientWidth; + var widthInMs = this.width * msPerPixel; + + if (align == 'right') { + isVisible = (this.data.start.getTime() > range.start ) && (this.data.start.getTime() - widthInMs < range.end); + } + else if (align == 'left') { + isVisible = (this.data.start.getTime() + widthInMs > range.start ) && (this.data.start.getTime() < range.end); + } + else { + // default or 'center' + isVisible = (this.data.start.getTime() + widthInMs/2 > range.start ) && (this.data.start.getTime() - widthInMs/2 < range.end); + } + return isVisible; }; /** diff --git a/lib/timeline/component/item/Item.js b/lib/timeline/component/item/Item.js index 743e5944..e50918a8 100644 --- a/lib/timeline/component/item/Item.js +++ b/lib/timeline/component/item/Item.js @@ -99,7 +99,6 @@ Item.prototype.setParent = function(parent) { * @returns {boolean} True if visible */ Item.prototype.isVisible = function(range) { - // Should be implemented by Item implementations return false; }; diff --git a/lib/timeline/component/item/PointItem.js b/lib/timeline/component/item/PointItem.js index a05b9982..10a2463c 100644 --- a/lib/timeline/component/item/PointItem.js +++ b/lib/timeline/component/item/PointItem.js @@ -43,9 +43,10 @@ PointItem.prototype = new Item (null, null, null); */ PointItem.prototype.isVisible = function(range) { // determine visibility - // TODO: account for the real width of the item. Right now we just add 1/4 to the window - var interval = (range.end - range.start) / 4; - return (this.data.start > range.start - interval) && (this.data.start < range.end + interval); + var msPerPixel = (range.end - range.start) / range.body.dom.center.clientWidth; + var widthInMs = this.width * msPerPixel; + + return (this.data.start.getTime() + widthInMs > range.start ) && (this.data.start < range.end); }; /** diff --git a/lib/timeline/component/item/RangeItem.js b/lib/timeline/component/item/RangeItem.js index 01c94ed2..8ec29991 100644 --- a/lib/timeline/component/item/RangeItem.js +++ b/lib/timeline/component/item/RangeItem.js @@ -43,14 +43,8 @@ RangeItem.prototype.baseClassName = 'vis-item vis-range'; */ RangeItem.prototype.isVisible = function(range) { // determine visibility -var isVisible = -// determine horizontal visibillity -(this.data.start < range.end) && -(this.data.end > range.start) && -// determine vertical visibillity -(this.parent.top < range.body.domProps.centerContainer.height - range.body.domProps.scrollTop) && -(this.parent.top + this.parent.height > - range.body.domProps.scrollTop) -return isVisible;}; + return (this.data.start < range.end) && (this.data.end > range.start); +}; /** * Repaint the item From b136380655cda868ef385a6f0ab77f7012045fe8 Mon Sep 17 00:00:00 2001 From: Uli Fahrer Date: Mon, 17 Oct 2016 14:34:59 +0200 Subject: [PATCH 13/43] Fix blur edge for dense networks (#2124) --- lib/network/modules/SelectionHandler.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/network/modules/SelectionHandler.js b/lib/network/modules/SelectionHandler.js index 8b48c1f6..8c5eaf37 100644 --- a/lib/network/modules/SelectionHandler.js +++ b/lib/network/modules/SelectionHandler.js @@ -534,8 +534,9 @@ class SelectionHandler { this.hoverObj.edges[edgeId].hover = false; delete this.hoverObj.edges[edgeId]; } - // if the blur remains the same and the object is undefined (mouse off), we blur the edge - else if (object === undefined) { + // if the blur remains the same and the object is undefined (mouse off) or another + // edge has been hovered, we blur the edge + else if (object === undefined || object instanceof Edge) { this.blurObject(this.hoverObj.edges[edgeId]); delete this.hoverObj.edges[edgeId]; hoverChanged = true; From 029b6ab684864f8b993b1932cc037d145adc7dd9 Mon Sep 17 00:00:00 2001 From: wimrijnders Date: Mon, 17 Oct 2016 15:35:29 +0200 Subject: [PATCH 14/43] Consolidated usage of getContext (#2157) --- lib/graph3d/Graph3d.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 01fe7445..5b953454 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -967,6 +967,17 @@ Graph3d.prototype.redraw = function() { this._redrawLegend(); }; + +/** + * Get drawing context without exposing canvas + */ +Graph3d.prototype._getContext = function() { + var canvas = this.frame.canvas; + var ctx = canvas.getContext('2d'); + return ctx; +}; + + /** * Clear the canvas before redrawing */ @@ -1024,8 +1035,7 @@ Graph3d.prototype._redrawLegend = function() { var left = right - width; var bottom = top + height; - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + var ctx = this._getContext(); ctx.lineWidth = 1; ctx.font = '14px arial'; // TODO: put in options @@ -1157,8 +1167,7 @@ Graph3d.prototype._redrawSlider = function() { */ Graph3d.prototype._redrawInfo = function() { if (this.dataFilter) { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + var ctx = this._getContext(); ctx.font = '14px arial'; // TODO: put in options ctx.lineStyle = 'gray'; @@ -1177,8 +1186,7 @@ Graph3d.prototype._redrawInfo = function() { * Redraw the axis */ Graph3d.prototype._redrawAxis = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), + var ctx = this._getContext(), from, to, step, prettyStep, text, xText, yText, zText, offset, xOffset, yOffset, @@ -1477,8 +1485,7 @@ Graph3d.prototype._hsv2rgb = function(H, S, V) { * This function can be used when the style is 'grid' */ Graph3d.prototype._redrawDataGrid = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), + var ctx = this._getContext(), point, right, top, cross, i, topSideVisible, fillStyle, strokeStyle, lineWidth, @@ -1624,8 +1631,7 @@ Graph3d.prototype._getStrokeWidth = function(point) { * This function can be used when the style is 'dot' or 'dot-line' */ Graph3d.prototype._redrawDataDot = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + var ctx = this._getContext(); var i; if (this.dataPoints === undefined || this.dataPoints.length <= 0) @@ -1720,8 +1726,7 @@ Graph3d.prototype._redrawDataDot = function() { * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' */ Graph3d.prototype._redrawDataBar = function() { - var canvas = this.frame.canvas; - var ctx = canvas.getContext('2d'); + var ctx = this._getContext(); var i, j, surface, corners; if (this.dataPoints === undefined || this.dataPoints.length <= 0) @@ -1862,8 +1867,7 @@ Graph3d.prototype._redrawDataBar = function() { * This function can be used when the style is 'line' */ Graph3d.prototype._redrawDataLine = function() { - var canvas = this.frame.canvas, - ctx = canvas.getContext('2d'), + var ctx = this._getContext(), point, i; if (this.dataPoints === undefined || this.dataPoints.length <= 0) From fed04410cd6a77b0b8740cee8e872a998782c764 Mon Sep 17 00:00:00 2001 From: wimrijnders Date: Mon, 17 Oct 2016 15:41:23 +0200 Subject: [PATCH 15/43] ignore '.directory' (#2158) --- .gitignore | 1 + CONTRIBUTING.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a182852b..0cfb188a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules .project .settings/ npm-debug.log +.directory # vim temporary files .*.sw[op] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6660fb3..252caf9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,7 @@ There are a few preferences regarding **code contributions**: - vis.js follows the node.js code style as described [here](http://nodeguide.com/style.html). - When implementing new features, please update the documentation accordingly. +- Make changes in the `develop` branch, not the `master` branch. - Send pull requests to the `develop` branch, not the `master` branch. - Only commit changes done in the source files under `lib`, not to the builds which are located in the folder `dist`. From 0330e2ff150611b32c52f07ef80452f872715648 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Mon, 17 Oct 2016 15:58:15 +0200 Subject: [PATCH 16/43] Added 2D line drawing method --- lib/graph3d/Graph3d.js | 106 +++++++++++++---------------------------- 1 file changed, 33 insertions(+), 73 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 5b953454..e13e53f7 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1182,6 +1182,23 @@ Graph3d.prototype._redrawInfo = function() { }; +/** + * Draw a line between 2d points 'from' and 'to'. + * + * If stroke style specified, set that as well. + */ +Graph3d.prototype._line = function(ctx, from, to, strokeStyle) { + if (strokeStyle !== undefined) { + ctx.strokeStyle = strokeStyle; + } + + ctx.beginPath(); + ctx.moveTo(from.x, from.y); + ctx.lineTo(to.x , to.y ); + ctx.stroke(); +} + + /** * Redraw the axis */ @@ -1216,28 +1233,16 @@ Graph3d.prototype._redrawAxis = function() { if (this.showGrid) { from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - ctx.strokeStyle = this.gridColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.gridColor); } else { from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); } yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; @@ -1273,28 +1278,16 @@ Graph3d.prototype._redrawAxis = function() { if (this.showGrid) { from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.gridColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.gridColor); } else { from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); } xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; @@ -1331,11 +1324,8 @@ Graph3d.prototype._redrawAxis = function() { while (!step.end()) { // TODO: make z-grid lines really 3d? from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(from.x - textMargin, from.y); - ctx.stroke(); + to = new Point2d(from.x - textMargin, from.y); + this._line(ctx, from, to, this.axisColor); ctx.textAlign = 'right'; ctx.textBaseline = 'middle'; @@ -1347,49 +1337,29 @@ Graph3d.prototype._redrawAxis = function() { ctx.lineWidth = 1; from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); // draw x-axis ctx.lineWidth = 1; // line at yMin xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); + this._line(ctx, xMin2d, xMax2d, this.axisColor); // line at ymax xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(xMin2d.x, xMin2d.y); - ctx.lineTo(xMax2d.x, xMax2d.y); - ctx.stroke(); + this._line(ctx, xMin2d, xMax2d, this.axisColor); // draw y-axis ctx.lineWidth = 1; // line at xMin from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); // line at xMax from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - ctx.strokeStyle = this.axisColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); + this._line(ctx, from, to, this.axisColor); // draw x-label var xLabel = this.xLabel; @@ -1591,10 +1561,7 @@ Graph3d.prototype._redrawDataGrid = function() { ctx.lineWidth = this._getStrokeWidth(point) * 2; ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(right.screen.x, right.screen.y); - ctx.stroke(); + this._line(ctx, point.screen, right.screen); } if (point !== undefined && top !== undefined) { @@ -1604,10 +1571,7 @@ Graph3d.prototype._redrawDataGrid = function() { ctx.lineWidth = this._getStrokeWidth(point) * 2; ctx.strokeStyle = this._hsv2rgb(h, 1, 1); - ctx.beginPath(); - ctx.moveTo(point.screen.x, point.screen.y); - ctx.lineTo(top.screen.x, top.screen.y); - ctx.stroke(); + this._line(ctx, point.screen, top.screen); } } } @@ -1665,11 +1629,7 @@ Graph3d.prototype._redrawDataDot = function() { //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin)); var from = this._convert3Dto2D(point.bottom); ctx.lineWidth = 1; - ctx.strokeStyle = this.gridColor; - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(point.screen.x, point.screen.y); - ctx.stroke(); + this._line(ctx, from, point.screen, this.gridColor); } // calculate radius for the circle From 4b235aba70fff46f9dc7492f6cb22e06f2d4ceee Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Mon, 17 Oct 2016 16:47:29 +0200 Subject: [PATCH 17/43] Translation of all data points to single method. --- lib/graph3d/Graph3d.js | 95 ++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 60 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index e13e53f7..d990a96c 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -226,6 +226,37 @@ Graph3d.prototype._convertTranslationToScreen = function(translation) { this.ycenter - by * this.frame.canvas.clientWidth); }; + +/** + * Calculate the translations and screen positions of all points + */ +Graph3d.prototype._calcTranslations = function(points, sort) { + if (sort === undefined) { + sort = true; + } + + for (var i = 0; i < points.length; i++) { + var point = points[i]; + point.trans = this._convertPointToTranslation(point.point); + point.screen = this._convertTranslationToScreen(point.trans); + + // calculate the translation of the point at the bottom (needed for sorting) + var transBottom = this._convertPointToTranslation(point.bottom); + point.dist = this.showPerspective ? transBottom.length() : -transBottom.z; + } + + if (!sort) { + return; + } + + // sort the points on depth of their (x,y) position (not on z) + var sortDepth = function (a, b) { + return b.dist - a.dist; + }; + points.sort(sortDepth); +}; + + /** * Set the background styling for the graph * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor @@ -1467,24 +1498,7 @@ Graph3d.prototype._redrawDataGrid = function() { if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception? - // calculate the translations and screen position of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - - // calculate the translation of the point at the bottom (needed for sorting) - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } - - // sort the points on depth of their (x,y) position (not on z) - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + this._calcTranslations(this.dataPoints); if (this.style === Graph3d.STYLE.SURFACE) { for (i = 0; i < this.dataPoints.length; i++) { @@ -1601,23 +1615,7 @@ Graph3d.prototype._redrawDataDot = function() { if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception? - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } - - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + this._calcTranslations(this.dataPoints); // draw the datapoints as colored circles var dotSize = this.frame.clientWidth * this.dotSizeRatio; // px @@ -1692,23 +1690,7 @@ Graph3d.prototype._redrawDataBar = function() { if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception? - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - - // calculate the distance from the point at the bottom to the camera - var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom); - this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z; - } - - // order the translated points by depth - var sortDepth = function (a, b) { - return b.dist - a.dist; - }; - this.dataPoints.sort(sortDepth); + this._calcTranslations(this.dataPoints); ctx.lineJoin = 'round'; ctx.lineCap = 'round'; @@ -1833,14 +1815,7 @@ Graph3d.prototype._redrawDataLine = function() { if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception? - // calculate the translations of all points - for (i = 0; i < this.dataPoints.length; i++) { - var trans = this._convertPointToTranslation(this.dataPoints[i].point); - var screen = this._convertTranslationToScreen(trans); - - this.dataPoints[i].trans = trans; - this.dataPoints[i].screen = screen; - } + this._calcTranslations(this.dataPoints, false); // start the line if (this.dataPoints.length > 0) { From 85222bfd64d2d1c7dd19b373398f5f8675ab1775 Mon Sep 17 00:00:00 2001 From: wimrijnders Date: Mon, 17 Oct 2016 17:44:22 +0200 Subject: [PATCH 18/43] throw real Error instances (#2160) --- lib/graph3d/Filter.js | 4 ++-- lib/graph3d/Graph3d.js | 8 ++++---- lib/graph3d/Slider.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/graph3d/Filter.js b/lib/graph3d/Filter.js index 2315104c..41d734a3 100644 --- a/lib/graph3d/Filter.js +++ b/lib/graph3d/Filter.js @@ -111,7 +111,7 @@ Filter.prototype.getValues = function() { */ Filter.prototype.getValue = function(index) { if (index >= this.values.length) - throw 'Error: index out of range'; + throw new Error('Index out of range'); return this.values[index]; }; @@ -164,7 +164,7 @@ Filter.prototype.setOnLoadCallback = function(callback) { */ Filter.prototype.selectValue = function(index) { if (index >= this.values.length) - throw 'Error: index out of range'; + throw new Error('Index out of range'); this.index = index; this.value = this.values[index]; diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index e13e53f7..c8814d77 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -249,7 +249,7 @@ Graph3d.prototype._setBackgroundColor = function(backgroundColor) { // use use defaults } else { - throw 'Unsupported type of backgroundColor'; + throw new Error('Unsupported type of backgroundColor'); } this.frame.style.backgroundColor = fill; @@ -333,7 +333,7 @@ Graph3d.prototype._determineColumnIndexes = function(data, style) { } } else { - throw 'Unknown style "' + this.style + '"'; + throw new Error('Unknown style "' + this.style + '"'); } }; @@ -702,7 +702,7 @@ Graph3d.prototype._resizeCanvas = function() { */ Graph3d.prototype.animationStart = function() { if (!this.frame.filter || !this.frame.filter.slider) - throw 'No animation available'; + throw new Error('No animation available'); this.frame.filter.slider.play(); }; @@ -937,7 +937,7 @@ Graph3d.prototype.setOptions = function (options) { */ Graph3d.prototype.redraw = function() { if (this.dataPoints === undefined) { - throw 'Error: graph data not initialized'; + throw new Error('Graph data not initialized'); } this._resizeCanvas(); diff --git a/lib/graph3d/Slider.js b/lib/graph3d/Slider.js index dd688e50..f6f21ecc 100644 --- a/lib/graph3d/Slider.js +++ b/lib/graph3d/Slider.js @@ -11,7 +11,7 @@ var util = require('../util'); */ function Slider(container, options) { if (container === undefined) { - throw 'Error: No container element defined'; + throw new Error('No container element defined'); } this.container = container; this.visible = (options && options.visible != undefined) ? options.visible : true; @@ -253,7 +253,7 @@ Slider.prototype.setIndex = function(index) { this.onChange(); } else { - throw 'Error: index out of range'; + throw new Error('Index out of range'); } }; From b84e9e48de834578bc22e02403af28d19424188e Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 17 Oct 2016 19:20:39 +0100 Subject: [PATCH 19/43] Removed restriction to allow clusters of a single node. (#2013) * Removed restriction to allow clusters of a single node; Default functionality remains the same; Also added new example * Add documentation for allowSingleNodeCluster, and removed excessive cluster() calls in example. * Changed documentation as per request. --- docs/network/index.html | 8 +- .../network/other/clustersOfclusters.html | 75 +++++++++++++++++++ lib/network/modules/Clustering.js | 7 +- 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 examples/network/other/clustersOfclusters.html diff --git a/docs/network/index.html b/docs/network/index.html index 0f8ef8ff..60d0dd47 100644 --- a/docs/network/index.html +++ b/docs/network/index.html @@ -1237,7 +1237,13 @@ var options = { node any way you want. This is also the style object that is provided in the processProperties function for - fine tuning. If undefined, default node options will be used. + fine tuning. If undefined, default node options will be used.

+ Default functionality only allows clustering if the cluster will contain 2 or more nodes. To allow clustering of single nodes you can use the allowSingleNodeCluster : true property. +
+    clusterNodeProperties: {
+        allowSingleNodeCluster: true
+    }
+
clusterEdgeProperties diff --git a/examples/network/other/clustersOfclusters.html b/examples/network/other/clustersOfclusters.html new file mode 100644 index 00000000..0e90bcf0 --- /dev/null +++ b/examples/network/other/clustersOfclusters.html @@ -0,0 +1,75 @@ + + + + + Cluster Test + + + + + +

+ Clusters can contain other clusters, but clusters of a single node is only possible by adding +

allowSingleNodeCluster: true
+to clusterNodeProperties
+In this example repeatedly clicking on the node with open the Clusters. +

+
+
+ + + diff --git a/lib/network/modules/Clustering.js b/lib/network/modules/Clustering.js index cb4d503e..f67d0da1 100644 --- a/lib/network/modules/Clustering.js +++ b/lib/network/modules/Clustering.js @@ -348,8 +348,11 @@ class ClusterEngine { * @private */ _cluster(childNodesObj, childEdgesObj, options, refreshData = true) { - // kill condition: no children so can't cluster or only one node in the cluster, don't bother - if (Object.keys(childNodesObj).length < 2) {return;} + // kill condition: no nodes don't bother + if (Object.keys(childNodesObj).length == 0) {return;} + + // allow clusters of 1 if options allow + if (Object.keys(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {return;} // check if this cluster call is not trying to cluster anything that is in another cluster. for (let nodeId in childNodesObj) { From a2350bb590f885c62d70184b6410a3e8dbff6357 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 06:30:01 +0200 Subject: [PATCH 20/43] Moved recurring code for StepNumber to start() method --- lib/graph3d/Graph3d.js | 24 ++++++++---------------- lib/graph3d/StepNumber.js | 22 +++++++++++++++++++--- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 1909ae76..4fbcd734 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1118,10 +1118,8 @@ Graph3d.prototype._redrawLegend = function() { var legendMin = isValueLegend ? this.valueMin : this.zMin; var legendMax = isValueLegend ? this.valueMax : this.zMax; var step = new StepNumber(legendMin, legendMax, (legendMax-legendMin)/5, true); - step.start(); - if (step.getCurrent() < legendMin) { - step.next(); - } + step.start(true); + var y; while (!step.end()) { y = bottom - (step.getCurrent() - legendMin) / (legendMax - legendMin) * height; @@ -1254,10 +1252,8 @@ Graph3d.prototype._redrawAxis = function() { ctx.lineWidth = 1; prettyStep = (this.defaultXStep === undefined); step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep); - step.start(); - if (step.getCurrent() < this.xMin) { - step.next(); - } + step.start(true); + while (!step.end()) { var x = step.getCurrent(); @@ -1301,10 +1297,8 @@ Graph3d.prototype._redrawAxis = function() { ctx.lineWidth = 1; prettyStep = (this.defaultYStep === undefined); step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep); - step.start(); - if (step.getCurrent() < this.yMin) { - step.next(); - } + step.start(true); + while (!step.end()) { if (this.showGrid) { from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); @@ -1346,10 +1340,8 @@ Graph3d.prototype._redrawAxis = function() { ctx.lineWidth = 1; prettyStep = (this.defaultZStep === undefined); step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); - step.start(); - if (step.getCurrent() < this.zMin) { - step.next(); - } + step.start(true); + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; while (!step.end()) { diff --git a/lib/graph3d/StepNumber.js b/lib/graph3d/StepNumber.js index 6c11a37c..72a73839 100644 --- a/lib/graph3d/StepNumber.js +++ b/lib/graph3d/StepNumber.js @@ -115,13 +115,29 @@ StepNumber.prototype.getStep = function () { }; /** - * Set the current value to the largest value smaller than start, which - * is a multiple of the step size + * Set the current to its starting value. + * + * By default, this will be the largest value smaller than start, which + * is a multiple of the step size. + * + * Parameters checkFirst is optional, default false. + * If set to true, move the current value one step if smaller than start. */ -StepNumber.prototype.start = function() { +StepNumber.prototype.start = function(checkFirst) { + if (checkFirst === undefined) { + checkFirst = false; + } + this._current = this._start - this._start % this._step; + + if (checkFirst) { + if (this.getCurrent() < this._start) { + this.next(); + } + } }; + /** * Do a step, add the step size to the current value */ From ccec638d5f65cd08b3efffa8b45f4f4ea8e4cb2d Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 06:52:38 +0200 Subject: [PATCH 21/43] Added method for drawing lines between 3D points --- lib/graph3d/Graph3d.js | 79 ++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 1909ae76..f5a40ab1 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1230,6 +1230,19 @@ Graph3d.prototype._line = function(ctx, from, to, strokeStyle) { } +/** + * Draw a line between 2d points 'from' and 'to'. + * + * If stroke style specified, set that as well. + */ +Graph3d.prototype._line3d = function(ctx, from, to, strokeStyle) { + var from2d = this._convert3Dto2D(from); + var to2d = this._convert3Dto2D(to); + + this._line(ctx, from2d, to2d, strokeStyle); +} + + /** * Redraw the axis */ @@ -1262,18 +1275,18 @@ Graph3d.prototype._redrawAxis = function() { var x = step.getCurrent(); if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - this._line(ctx, from, to, this.gridColor); + from = new Point3d(x, this.yMin, this.zMin); + to = new Point3d(x, this.yMax, this.zMin); + this._line3d(ctx, from, to, this.gridColor); } else { - from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(x, this.yMin, this.zMin); + to = new Point3d(x, this.yMin+gridLenX, this.zMin); + this._line3d(ctx, from, to, this.axisColor); - from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin)); - to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(x, this.yMax, this.zMin); + to = new Point3d(x, this.yMax-gridLenX, this.zMin); + this._line3d(ctx, from, to, this.axisColor); } yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; @@ -1307,18 +1320,18 @@ Graph3d.prototype._redrawAxis = function() { } while (!step.end()) { if (this.showGrid) { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - this._line(ctx, from, to, this.gridColor); + from = new Point3d(this.xMin, step.getCurrent(), this.zMin); + to = new Point3d(this.xMax, step.getCurrent(), this.zMin); + this._line3d(ctx, from, to, this.gridColor); } else { - from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(this.xMin, step.getCurrent(), this.zMin); + to = new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin); + this._line3d(ctx, from, to, this.axisColor); - from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(this.xMax, step.getCurrent(), this.zMin); + to = new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin); + this._line3d(ctx, from, to, this.axisColor); } xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; @@ -1366,31 +1379,31 @@ Graph3d.prototype._redrawAxis = function() { step.next(); } ctx.lineWidth = 1; - from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(xText, yText, this.zMin); + to = new Point3d(xText, yText, this.zMax); + this._line3d(ctx, from, to, this.axisColor); // draw x-axis ctx.lineWidth = 1; // line at yMin - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - this._line(ctx, xMin2d, xMax2d, this.axisColor); + xMin2d = new Point3d(this.xMin, this.yMin, this.zMin); + xMax2d = new Point3d(this.xMax, this.yMin, this.zMin); + this._line3d(ctx, xMin2d, xMax2d, this.axisColor); // line at ymax - xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - this._line(ctx, xMin2d, xMax2d, this.axisColor); + xMin2d = new Point3d(this.xMin, this.yMax, this.zMin); + xMax2d = new Point3d(this.xMax, this.yMax, this.zMin); + this._line3d(ctx, xMin2d, xMax2d, this.axisColor); // draw y-axis ctx.lineWidth = 1; // line at xMin - from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(this.xMin, this.yMin, this.zMin); + to = new Point3d(this.xMin, this.yMax, this.zMin); + this._line3d(ctx, from, to, this.axisColor); // line at xMax - from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin)); - to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin)); - this._line(ctx, from, to, this.axisColor); + from = new Point3d(this.xMax, this.yMin, this.zMin); + to = new Point3d(this.xMax, this.yMax, this.zMin); + this._line3d(ctx, from, to, this.axisColor); // draw x-label var xLabel = this.xLabel; From 9e13640d8dc2f26c942bc698e21097d8a340b16d Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 07:17:42 +0200 Subject: [PATCH 22/43] Consolidated code for drawing x-axis label --- lib/graph3d/Graph3d.js | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 1909ae76..986a7016 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1230,6 +1230,32 @@ Graph3d.prototype._line = function(ctx, from, to, strokeStyle) { } +Graph3d.prototype.drawAxisLabelX = function(ctx, point3d, text, armAngle, yMargin) { + if (yMargin === undefined) { + yMargin = 0; + } + + var point2d = this._convert3Dto2D(point3d); + + if (Math.cos(armAngle * 2) > 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + point2d.y += yMargin; + } + else if (Math.sin(armAngle * 2) < 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + + ctx.fillStyle = this.axisColor; + ctx.fillText(text, point2d.x, point2d.y); +} + + /** * Redraw the axis */ @@ -1276,23 +1302,10 @@ Graph3d.prototype._redrawAxis = function() { this._line(ctx, from, to, this.axisColor); } - yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; - text = this._convert3Dto2D(new Point3d(x, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.axisColor; - ctx.fillText(' ' + this.xValueLabel(step.getCurrent()) + ' ', text.x, text.y); + yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; + var point3d = new Point3d(x, yText, this.zMin); + var msg = ' ' + this.xValueLabel(x) + ' '; + this.drawAxisLabelX(ctx, point3d, msg, armAngle, textMargin); step.next(); } @@ -1396,23 +1409,10 @@ Graph3d.prototype._redrawAxis = function() { var xLabel = this.xLabel; if (xLabel.length > 0) { yOffset = 0.1 / this.scale.y; - xText = (this.xMin + this.xMax) / 2; - yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) > 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) < 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.axisColor; - ctx.fillText(xLabel, text.x, text.y); + xText = (this.xMin + this.xMax) / 2; + yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; + text = new Point3d(xText, yText, this.zMin); + this.drawAxisLabelX(ctx, text, xLabel, armAngle); } // draw y-label From 9b5eb3f4da3d4029e380e728f83b6d4d07cf8313 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 15:43:00 +0200 Subject: [PATCH 23/43] Added methods for drawing Y and Z axis labels --- lib/graph3d/Graph3d.js | 130 ++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index ec556b95..c43f507b 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1254,6 +1254,48 @@ Graph3d.prototype.drawAxisLabelX = function(ctx, point3d, text, armAngle, yMargi } +Graph3d.prototype.drawAxisLabelY = function(ctx, point3d, text, armAngle, yMargin) { + if (yMargin === undefined) { + yMargin = 0; + } + + var point2d = this._convert3Dto2D(point3d); + + if (Math.cos(armAngle * 2) < 0) { + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + point2d.y += yMargin; + } + else if (Math.sin(armAngle * 2) > 0){ + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + } + else { + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + } + + ctx.fillStyle = this.axisColor; + ctx.fillText(text, point2d.x, point2d.y); +} + + +Graph3d.prototype.drawAxisLabelZ = function(ctx, point3d, text, offset) { + if (offset === undefined) { + offset = 0; + } + + var point2d = this._convert3Dto2D(point3d); + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.axisColor; + ctx.fillText(text, point2d.x - offset, point2d.y); +}; + + +/** + + /** * Draw a line between 2d points 'from' and 'to'. * @@ -1326,38 +1368,27 @@ Graph3d.prototype._redrawAxis = function() { step.start(true); while (!step.end()) { + var y = step.getCurrent(); + if (this.showGrid) { - from = new Point3d(this.xMin, step.getCurrent(), this.zMin); - to = new Point3d(this.xMax, step.getCurrent(), this.zMin); + from = new Point3d(this.xMin, y, this.zMin); + to = new Point3d(this.xMax, y, this.zMin); this._line3d(ctx, from, to, this.gridColor); } else { - from = new Point3d(this.xMin, step.getCurrent(), this.zMin); - to = new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin); + from = new Point3d(this.xMin, y, this.zMin); + to = new Point3d(this.xMin+gridLenY, y, this.zMin); this._line3d(ctx, from, to, this.axisColor); - from = new Point3d(this.xMax, step.getCurrent(), this.zMin); - to = new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin); + from = new Point3d(this.xMax, y, this.zMin); + to = new Point3d(this.xMax-gridLenY, y, this.zMin); this._line3d(ctx, from, to, this.axisColor); } - xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; - text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - text.y += textMargin; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.axisColor; - ctx.fillText(' ' + this.yValueLabel(step.getCurrent()) + ' ', text.x, text.y); + xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; + point3d = new Point3d(xText, y, this.zMin); + var msg = ' ' + this.yValueLabel(y) + ' '; + this.drawAxisLabelY(ctx, point3d, msg, armAngle, textMargin); step.next(); } @@ -1370,19 +1401,22 @@ Graph3d.prototype._redrawAxis = function() { xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + while (!step.end()) { + var z = step.getCurrent(); + // TODO: make z-grid lines really 3d? - from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent())); - to = new Point2d(from.x - textMargin, from.y); - this._line(ctx, from, to, this.axisColor); + var from3d = new Point3d(xText, yText, z); + var from2d = this._convert3Dto2D(from3d); + to = new Point2d(from2d.x - textMargin, from2d.y); + this._line(ctx, from2d, to, this.axisColor); - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.axisColor; - ctx.fillText(this.zValueLabel(step.getCurrent()) + ' ', from.x - 5, from.y); + var msg = this.zValueLabel(z) + ' '; + this.drawAxisLabelZ(ctx, from3d, msg, 5); step.next(); } + ctx.lineWidth = 1; from = new Point3d(xText, yText, this.zMin); to = new Point3d(xText, yText, this.zMax); @@ -1424,37 +1458,23 @@ Graph3d.prototype._redrawAxis = function() { var yLabel = this.yLabel; if (yLabel.length > 0) { xOffset = 0.1 / this.scale.x; - xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; - yText = (this.yMin + this.yMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin)); - if (Math.cos(armAngle * 2) < 0) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - } - else if (Math.sin(armAngle * 2) > 0){ - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - } - else { - ctx.textAlign = 'left'; - ctx.textBaseline = 'middle'; - } - ctx.fillStyle = this.axisColor; - ctx.fillText(yLabel, text.x, text.y); + xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; + yText = (this.yMin + this.yMax) / 2; + text = new Point3d(xText, yText, this.zMin); + + this.drawAxisLabelY(ctx, text, yLabel, armAngle); } // draw z-label var zLabel = this.zLabel; if (zLabel.length > 0) { offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; - zText = (this.zMin + this.zMax) / 2; - text = this._convert3Dto2D(new Point3d(xText, yText, zText)); - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.axisColor; - ctx.fillText(zLabel, text.x - offset, text.y); + xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; + yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + zText = (this.zMin + this.zMax) / 2; + text = new Point3d(xText, yText, zText); + + this.drawAxisLabelZ(ctx, text, zLabel, offset); } }; From 674813dcade0f74c5013486a65be7d5680fe06c6 Mon Sep 17 00:00:00 2001 From: wimrijnders Date: Tue, 18 Oct 2016 16:35:50 +0200 Subject: [PATCH 24/43] Uniform handling of common user options (#2168) --- lib/graph3d/Graph3d.js | 92 +++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index c43f507b..b3a59f4e 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -8,6 +8,65 @@ var Filter = require('./Filter'); var Slider = require('./Slider'); var StepNumber = require('./StepNumber'); +// ----------------------------------------------------------------------------- +// Definitions private to module +// ----------------------------------------------------------------------------- + +/** + * Field names in the options hash which are of relevance to the user. + * + * Specifically, these are the fields which require no special handling, + * and can be directly copied over. + */ +var OPTIONKEYS = [ + 'width', + 'height', + 'filterLabel', + 'legendLabel', + 'xLabel', + 'yLabel', + 'zLabel', + 'xValueLabel', + 'yValueLabel', + 'zValueLabel', + 'showGrid', + 'showPerspective', + 'showShadow', + 'showAnimationControls', + 'keepAspectRatio', + 'verticalRatio', + 'animationInterval', + 'animationPreload', + 'animationAutoStart', + 'axisColor', + 'gridColor' +]; + + +/** + * Copy fields from src to dst in a controlled manner. + * + * Only the fields mentioned in array 'fields' will be copied over, + * and only if these are actually defined. + * + * @param fields array with names of fields to copy + */ +function safeCopy(src, dst, fields) { + for (var i in fields) { + var field = fields[i]; + + if (src[field] !== undefined) { + dst[field] = src[field]; + } + } +} + + + +// ----------------------------------------------------------------------------- +// Class Graph3d +// ----------------------------------------------------------------------------- + /** * @constructor Graph3d * Graph3d displays data in 3d. @@ -867,24 +926,14 @@ Graph3d.prototype.setOptions = function (options) { if (options !== undefined) { // retrieve parameter values - if (options.width !== undefined) this.width = options.width; - if (options.height !== undefined) this.height = options.height; + // Handle the parameters which can be simply copied over + safeCopy(options, this, OPTIONKEYS); + + // Handle the rest of the parameters if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; - - if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; - if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; - if (options.xLabel !== undefined) this.xLabel = options.xLabel; - if (options.yLabel !== undefined) this.yLabel = options.yLabel; - if (options.zLabel !== undefined) this.zLabel = options.zLabel; - - if (options.xValueLabel !== undefined) this.xValueLabel = options.xValueLabel; - if (options.yValueLabel !== undefined) this.yValueLabel = options.yValueLabel; - if (options.zValueLabel !== undefined) this.zValueLabel = options.zValueLabel; - - if (options.dotSizeRatio !== undefined) this.dotSizeRatio = options.dotSizeRatio; if (options.style !== undefined) { var styleNumber = this._getStyleNumber(options.style); @@ -892,21 +941,10 @@ Graph3d.prototype.setOptions = function (options) { this.style = styleNumber; } } - if (options.showGrid !== undefined) this.showGrid = options.showGrid; - if (options.showPerspective !== undefined) this.showPerspective = options.showPerspective; - if (options.showShadow !== undefined) this.showShadow = options.showShadow; - if (options.tooltip !== undefined) this.showTooltip = options.tooltip; - if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls; - if (options.keepAspectRatio !== undefined) this.keepAspectRatio = options.keepAspectRatio; - if (options.verticalRatio !== undefined) this.verticalRatio = options.verticalRatio; - - if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval; - if (options.animationPreload !== undefined) this.animationPreload = options.animationPreload; - if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart; + if (options.tooltip !== undefined) this.showTooltip = options.tooltip; if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth; - if (options.xMin !== undefined) this.defaultXMin = options.xMin; if (options.xStep !== undefined) this.defaultXStep = options.xStep; if (options.xMax !== undefined) this.defaultXMax = options.xMax; @@ -928,8 +966,6 @@ Graph3d.prototype.setOptions = function (options) { } // colors - if (options.axisColor !== undefined) this.axisColor = options.axisColor; - if (options.gridColor !== undefined) this.gridColor = options.gridColor; if (options.dataColor) { if (typeof options.dataColor === 'string') { this.dataColor.fill = options.dataColor; From f84743053edd9fbd5b29d17453d4a95843785c76 Mon Sep 17 00:00:00 2001 From: Zachariah Brown Date: Tue, 18 Oct 2016 10:56:40 -0400 Subject: [PATCH 25/43] Adds oldData to the update event payload in dataview to match dataset. --- lib/DataView.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/DataView.js b/lib/DataView.js index 32a7325a..fb779c7f 100644 --- a/lib/DataView.js +++ b/lib/DataView.js @@ -300,6 +300,7 @@ DataView.prototype._onEvent = function (event, params, senderId) { var ids = params && params.items; var data = this._data; var updatedData = []; + var oldData = []; var added = []; var updated = []; var removed = []; @@ -330,6 +331,7 @@ DataView.prototype._onEvent = function (event, params, senderId) { if (this._ids[id]) { updated.push(id); updatedData.push(params.data[i]); + oldData.push(params.oldData[i]); } else { this._ids[id] = true; @@ -368,7 +370,7 @@ DataView.prototype._onEvent = function (event, params, senderId) { this._trigger('add', {items: added}, senderId); } if (updated.length) { - this._trigger('update', {items: updated, data: updatedData}, senderId); + this._trigger('update', {items: updated, data: updatedData, oldData: oldData}, senderId); } if (removed.length) { this._trigger('remove', {items: removed}, senderId); From ffc54474352133020b2674cae7ab8d388985fda1 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 17:53:21 +0200 Subject: [PATCH 26/43] Replaced sin/cos usage in drawAxis() with unit vector --- lib/graph3d/Graph3d.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index b3a59f4e..76d5aaa0 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -1360,10 +1360,11 @@ Graph3d.prototype._redrawAxis = function() { ctx.font = 24 / this.camera.getArmLength() + 'px arial'; // calculate the length for the short grid lines - var gridLenX = 0.025 / this.scale.x; - var gridLenY = 0.025 / this.scale.y; + var gridLenX = 0.025 / this.scale.x; + var gridLenY = 0.025 / this.scale.y; var textMargin = 5 / this.camera.getArmLength(); // px - var armAngle = this.camera.getArmRotation().horizontal; + var armAngle = this.camera.getArmRotation().horizontal; + var armVector = new Point2d(Math.cos(armAngle), Math.sin(armAngle)); // draw x-grid lines ctx.lineWidth = 1; @@ -1389,7 +1390,7 @@ Graph3d.prototype._redrawAxis = function() { this._line3d(ctx, from, to, this.axisColor); } - yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax; + yText = (armVector.x > 0) ? this.yMin : this.yMax; var point3d = new Point3d(x, yText, this.zMin); var msg = ' ' + this.xValueLabel(x) + ' '; this.drawAxisLabelX(ctx, point3d, msg, armAngle, textMargin); @@ -1421,7 +1422,7 @@ Graph3d.prototype._redrawAxis = function() { this._line3d(ctx, from, to, this.axisColor); } - xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax; + xText = (armVector.y > 0) ? this.xMin : this.xMax; point3d = new Point3d(xText, y, this.zMin); var msg = ' ' + this.yValueLabel(y) + ' '; this.drawAxisLabelY(ctx, point3d, msg, armAngle, textMargin); @@ -1435,8 +1436,8 @@ Graph3d.prototype._redrawAxis = function() { step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep); step.start(true); - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + xText = (armVector.x > 0) ? this.xMin : this.xMax; + yText = (armVector.y < 0) ? this.yMin : this.yMax; while (!step.end()) { var z = step.getCurrent(); @@ -1485,7 +1486,7 @@ Graph3d.prototype._redrawAxis = function() { if (xLabel.length > 0) { yOffset = 0.1 / this.scale.y; xText = (this.xMin + this.xMax) / 2; - yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset; + yText = (armVector.x > 0) ? this.yMin - yOffset: this.yMax + yOffset; text = new Point3d(xText, yText, this.zMin); this.drawAxisLabelX(ctx, text, xLabel, armAngle); } @@ -1494,7 +1495,7 @@ Graph3d.prototype._redrawAxis = function() { var yLabel = this.yLabel; if (yLabel.length > 0) { xOffset = 0.1 / this.scale.x; - xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset; + xText = (armVector.y > 0) ? this.xMin - xOffset : this.xMax + xOffset; yText = (this.yMin + this.yMax) / 2; text = new Point3d(xText, yText, this.zMin); @@ -1505,8 +1506,8 @@ Graph3d.prototype._redrawAxis = function() { var zLabel = this.zLabel; if (zLabel.length > 0) { offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis? - xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax; - yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax; + xText = (armVector.x > 0) ? this.xMin : this.xMax; + yText = (armVector.y < 0) ? this.yMin : this.yMax; zText = (this.zMin + this.zMax) / 2; text = new Point3d(xText, yText, zText); From b2e0eb9b739b222a03708e9b127b93efc4700807 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 19:04:10 +0200 Subject: [PATCH 27/43] Added structure for default values --- lib/graph3d/Graph3d.js | 122 +++++++++++++++++++++++++++++++---------- 1 file changed, 93 insertions(+), 29 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index b3a59f4e..f715b18e 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -44,7 +44,74 @@ var OPTIONKEYS = [ /** - * Copy fields from src to dst in a controlled manner. + * Default values for certain option fields. + * + * These are the values used when a Graph3d instance is initialized + * without custom settings. + * + * If a field is not in this list, a default value of 'undefined' can + * be assumed. Of course, it does no harm to set a field explicitly to + * 'undefined' here. + * + * A value of 'undefined' here normally means: + * + * 'derive from current data and graph style' + * + * In the code, this is indicated by the comment 'auto by default'. + */ +var DEFAULTS = { + width : '400px', + height : '400px', + filterLabel : 'time', + legendLabel : 'value', + xLabel : 'poep', + yLabel : 'y', + zLabel : 'z', + xValueLabel : function(v) { return v; }, + yValueLabel : function(v) { return v; }, + zValueLabel : function(v) { return v; }, + showGrid : true, + showPerspective : true, + showShadow : false, + keepAspectRatio : true, + verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube' + animationInterval: 1000, // milliseconds + animationPreload : false, + axisColor : '#4D4D4D', + gridColor : '#D3D3D3' + + + // Following not in defaults (yet) but present in user settings + // These will be initialized as 'undefined' + //'showAnimationControls', + //'animationAutoStart' +}; + + + +/** + * forcibly copy fields from src to dst in a controlled manner. + * + * A given field in dst will always be overwitten. If this field + * is undefined or not present in src, the field in dst will + * be explicitly set to undefined. + * + * The intention here is to be able to reset all option fields. + * + * Only the fields mentioned in array 'fields' will be handled. + * + * @param fields array with names of fields to copy + */ +function forceCopy(src, dst, fields) { + for (var i in fields) { + var field = fields[i]; + dst[field] = src[field]; + } +} + + +/** + * Copy fields from src to dst in a safe and controlled manner. * * Only the fields mentioned in array 'fields' will be copied over, * and only if these are actually defined. @@ -85,45 +152,41 @@ function Graph3d(container, data, options) { // create variables and set default values this.containerElement = container; - this.width = '400px'; - this.height = '400px'; + + this.dataTable = null; // The original data table + this.dataPoints = null; // The table with point objects + + + // + // Start Settings + // + + // Handle the defaults which can be simply copied over + forceCopy(DEFAULTS, this, OPTIONKEYS); + + // Following are internal fields, not part of the user settings this.margin = 10; // px + this.showGrayBottom = false; // TODO: this does not work correctly + this.showTooltip = false; + this.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width + + // The rest of the fields. + // These require special attention in some way + // TODO: handle these + this.defaultXCenter = '55%'; this.defaultYCenter = '50%'; - this.xLabel = 'x'; - this.yLabel = 'y'; - this.zLabel = 'z'; - - var passValueFn = function(v) { return v; }; - this.xValueLabel = passValueFn; - this.yValueLabel = passValueFn; - this.zValueLabel = passValueFn; - - this.filterLabel = 'time'; - this.legendLabel = 'value'; this.showLegend = undefined; // auto by default (based on graph style) this.style = Graph3d.STYLE.DOT; - this.showPerspective = true; - this.showGrid = true; - this.keepAspectRatio = true; - this.showShadow = false; - this.showGrayBottom = false; // TODO: this does not work correctly - this.showTooltip = false; - this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' - this.animationInterval = 1000; // milliseconds - this.animationPreload = false; this.camera = new Camera(); this.camera.setArmRotation(1.0, 0.5); this.camera.setArmLength(1.7); this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? - this.dataTable = null; // The original data table - this.dataPoints = null; // The table with point objects - // the column indexes this.colX = undefined; this.colY = undefined; @@ -147,15 +210,16 @@ function Graph3d(container, data, options) { // TODO: customize axis range // colors - this.axisColor = '#4D4D4D'; - this.gridColor = '#D3D3D3'; this.dataColor = { fill: '#7DC1FF', stroke: '#3267D2', strokeWidth: 1 // px }; - this.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width + + // + // End Settings + // // create a frame and canvas this.create(); From b21f5a15df64bd332c65d5df2da6547ebd633d70 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 19:07:40 +0200 Subject: [PATCH 28/43] Fixed typo --- lib/graph3d/Graph3d.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index f715b18e..6511c2fb 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -64,7 +64,7 @@ var DEFAULTS = { height : '400px', filterLabel : 'time', legendLabel : 'value', - xLabel : 'poep', + xLabel : 'x', yLabel : 'y', zLabel : 'z', xValueLabel : function(v) { return v; }, From 165aa03e13aa40e2dc87d9f8c2a1fc04ba64a35a Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Tue, 18 Oct 2016 19:30:27 +0200 Subject: [PATCH 29/43] Added xCenter and yCenter to defaults --- lib/graph3d/Graph3d.js | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 6511c2fb..1612bae9 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -39,7 +39,9 @@ var OPTIONKEYS = [ 'animationPreload', 'animationAutoStart', 'axisColor', - 'gridColor' + 'gridColor', + 'xCenter', + 'yCenter' ]; @@ -78,7 +80,9 @@ var DEFAULTS = { animationInterval: 1000, // milliseconds animationPreload : false, axisColor : '#4D4D4D', - gridColor : '#D3D3D3' + gridColor : '#D3D3D3', + xCenter : '55%', + yCenter : '50%' // Following not in defaults (yet) but present in user settings @@ -174,9 +178,6 @@ function Graph3d(container, data, options) { // These require special attention in some way // TODO: handle these - this.defaultXCenter = '55%'; - this.defaultYCenter = '50%'; - this.showLegend = undefined; // auto by default (based on graph style) this.style = Graph3d.STYLE.DOT; @@ -345,8 +346,8 @@ Graph3d.prototype._convertTranslationToScreen = function(translation) { // shift and scale the point to the center of the screen // use the width of the graph to scale both horizontally and vertically. return new Point2d( - this.xcenter + bx * this.frame.canvas.clientWidth, - this.ycenter - by * this.frame.canvas.clientWidth); + this.currentXCenter + bx * this.frame.canvas.clientWidth, + this.currentYCenter - by * this.frame.canvas.clientWidth); }; @@ -873,30 +874,30 @@ Graph3d.prototype.animationStop = function() { /** - * Resize the center position based on the current values in this.defaultXCenter - * and this.defaultYCenter (which are strings with a percentage or a value - * in pixels). The center positions are the variables this.xCenter - * and this.yCenter + * Resize the center position based on the current values in this.xCenter + * and this.yCenter (which are strings with a percentage or a value + * in pixels). The center positions are the variables this.currentXCenter + * and this.currentYCenter */ Graph3d.prototype._resizeCenter = function() { // calculate the horizontal center position - if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { - this.xcenter = - parseFloat(this.defaultXCenter) / 100 * + if (this.xCenter.charAt(this.xCenter.length-1) === '%') { + this.currentXCenter = + parseFloat(this.xCenter) / 100 * this.frame.canvas.clientWidth; } else { - this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px + this.currentXCenter = parseFloat(this.xCenter); // supposed to be in px } // calculate the vertical center position - if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { - this.ycenter = - parseFloat(this.defaultYCenter) / 100 * + if (this.yCenter.charAt(this.yCenter.length-1) === '%') { + this.currentYCenter = + parseFloat(this.yCenter) / 100 * (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); } else { - this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px + this.currentYCenter = parseFloat(this.yCenter); // supposed to be in px } }; @@ -995,8 +996,6 @@ Graph3d.prototype.setOptions = function (options) { safeCopy(options, this, OPTIONKEYS); // Handle the rest of the parameters - if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; - if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; if (options.style !== undefined) { From 7c6248626bafe871f21bd66a530ba3e774501a93 Mon Sep 17 00:00:00 2001 From: Zachariah Brown Date: Tue, 18 Oct 2016 14:25:28 -0400 Subject: [PATCH 30/43] Re-ordered keys to match other usage. --- lib/DataView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/DataView.js b/lib/DataView.js index fb779c7f..ba7a864e 100644 --- a/lib/DataView.js +++ b/lib/DataView.js @@ -370,7 +370,7 @@ DataView.prototype._onEvent = function (event, params, senderId) { this._trigger('add', {items: added}, senderId); } if (updated.length) { - this._trigger('update', {items: updated, data: updatedData, oldData: oldData}, senderId); + this._trigger('update', {items: updated, oldData: oldData, data: updatedData}, senderId); } if (removed.length) { this._trigger('remove', {items: removed}, senderId); From 1446540a26b9c69bd6a25fe11f208c399b3d6e70 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Wed, 19 Oct 2016 09:27:08 +0200 Subject: [PATCH 31/43] Added handling of settings backgroundColor and dataColor --- lib/graph3d/Graph3d.js | 127 ++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 41 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 19bc59ef..61a6cdf6 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -82,13 +82,23 @@ var DEFAULTS = { axisColor : '#4D4D4D', gridColor : '#D3D3D3', xCenter : '55%', - yCenter : '50%' + yCenter : '50%', // Following not in defaults (yet) but present in user settings // These will be initialized as 'undefined' //'showAnimationControls', //'animationAutoStart' + + // Following not in OPTIONKEYS because they require special handling, + + backgroundColor : undefined, + + dataColor : { + fill : '#7DC1FF', + stroke : '#3267D2', + strokeWidth: 1 // px + } }; @@ -160,6 +170,8 @@ function Graph3d(container, data, options) { this.dataTable = null; // The original data table this.dataPoints = null; // The table with point objects + // create a frame and canvas + this.create(); // // Start Settings @@ -174,6 +186,9 @@ function Graph3d(container, data, options) { this.showTooltip = false; this.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width + // Handle the more complex ('special') fields + this._setSpecialSettings(DEFAULTS, this); + // The rest of the fields. // These require special attention in some way // TODO: handle these @@ -210,21 +225,10 @@ function Graph3d(container, data, options) { this.yBarWidth = 1; // TODO: customize axis range - // colors - this.dataColor = { - fill: '#7DC1FF', - stroke: '#3267D2', - strokeWidth: 1 // px - }; - - // // End Settings // - // create a frame and canvas - this.create(); - // apply options (also when undefined) this.setOptions(options); @@ -381,11 +385,41 @@ Graph3d.prototype._calcTranslations = function(points, sort) { }; +// ----------------------------------------------------------------------------- +// Methods for handling settings +// ----------------------------------------------------------------------------- + + +/** + * Special handling for certain parameters + * + * 'Special' here means: setting requires more than a simple copy + */ +Graph3d.prototype._setSpecialSettings = function(src, dst) { + + if (src.backgroundColor !== undefined) { + this._setBackgroundColor(src.backgroundColor, dst); + } + + this._setDataColor(src.dataColor, dst); + +/* TODO + setStyle(src.style, dst); + + if (src.tooltip !== undefined) { + dst.showTooltip = src.tooltip; + } + + setCameraPosition(src.cameraPosition, dst); +End TODO */ +} + + /** * Set the background styling for the graph * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor */ -Graph3d.prototype._setBackgroundColor = function(backgroundColor) { +Graph3d.prototype._setBackgroundColor = function(backgroundColor, dst) { var fill = 'white'; var stroke = 'gray'; var strokeWidth = 1; @@ -400,20 +434,49 @@ Graph3d.prototype._setBackgroundColor = function(backgroundColor) { if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; } - else if (backgroundColor === undefined) { - // use use defaults - } else { throw new Error('Unsupported type of backgroundColor'); } - this.frame.style.backgroundColor = fill; - this.frame.style.borderColor = stroke; - this.frame.style.borderWidth = strokeWidth + 'px'; - this.frame.style.borderStyle = 'solid'; + dst.frame.style.backgroundColor = fill; + dst.frame.style.borderColor = stroke; + dst.frame.style.borderWidth = strokeWidth + 'px'; + dst.frame.style.borderStyle = 'solid'; }; +Graph3d.prototype._setDataColor = function(dataColor, dst) { + if (dataColor === undefined) { + return; // Nothing to do + } + + if (dst.dataColor === undefined) { + dst.dataColor = {}; + } + + if (typeof dataColor === 'string') { + dst.dataColor.fill = dataColor; + dst.dataColor.stroke = dataColor; + } + else { + if (dataColor.fill) { + dst.dataColor.fill = dataColor.fill; + } + if (dataColor.stroke) { + dst.dataColor.stroke = dataColor.stroke; + } + if (dataColor.strokeWidth !== undefined) { + dst.dataColor.strokeWidth = dataColor.strokeWidth; + } + } +} + + +// ----------------------------------------------------------------------------- +// End methods for handling settings +// ----------------------------------------------------------------------------- + + /// enumerate the available styles Graph3d.STYLE = { BAR: 0, @@ -995,6 +1058,9 @@ Graph3d.prototype.setOptions = function (options) { // Handle the parameters which can be simply copied over safeCopy(options, this, OPTIONKEYS); + // Handle the more complex ('special') fields + this._setSpecialSettings(options, this); + // Handle the rest of the parameters if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; @@ -1019,7 +1085,6 @@ Graph3d.prototype.setOptions = function (options) { if (options.zMax !== undefined) this.defaultZMax = options.zMax; if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; - if (options.backgroundColor !== undefined) this._setBackgroundColor(options.backgroundColor); if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; @@ -1027,26 +1092,6 @@ Graph3d.prototype.setOptions = function (options) { this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); this.camera.setArmLength(cameraPosition.distance); } - - // colors - if (options.dataColor) { - if (typeof options.dataColor === 'string') { - this.dataColor.fill = options.dataColor; - this.dataColor.stroke = options.dataColor; - } - else { - if (options.dataColor.fill) { - this.dataColor.fill = options.dataColor.fill; - } - if (options.dataColor.stroke) { - this.dataColor.stroke = options.dataColor.stroke; - } - if (options.dataColor.strokeWidth !== undefined) { - this.dataColor.strokeWidth = options.dataColor.strokeWidth; - } - } - } - } this.setSize(this.width, this.height); From f5fe722f1f0e138912e630256482d3500da840d1 Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Wed, 19 Oct 2016 09:57:49 +0200 Subject: [PATCH 32/43] Managing help offers (#2178) * removed reference to the style-guide * added a how-to-help; added a document describing the current maintainer status; fixes #2170; closes #1781 * listing the members of the support team * use search before creating a new issue * fixes typos --- CONTRIBUTING.md | 32 ++++++++------------- misc/how_to_help.md | 67 ++++++++++++++++++++++++++++++++++++++++++++ misc/we_need_help.md | 15 ++++++++++ 3 files changed, 94 insertions(+), 20 deletions(-) create mode 100644 misc/how_to_help.md create mode 100644 misc/we_need_help.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 252caf9c..414327c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,14 @@ ## Contributing -Contributions to the vis.js library are very welcome! We can't do this alone. - -You can contribute in different ways: spread the word, report bugs, come up with -ideas and suggestions, and contribute to the code. - -If you have any **general question** on how to use the vis.js library in your -project please check out -[stackoverflow](http://stackoverflow.com/questions/tagged/vis.js) for that. - -There are a few preferences regarding **code contributions**: - -- vis.js follows the node.js code style as described - [here](http://nodeguide.com/style.html). -- When implementing new features, please update the documentation accordingly. -- Make changes in the `develop` branch, not the `master` branch. -- Send pull requests to the `develop` branch, not the `master` branch. -- Only commit changes done in the source files under `lib`, not to the builds - which are located in the folder `dist`. - -Thanks! +[Contributions](//github.com/almende/vis/blob/master/misc/how_to_help.md) to the vis.js library are very welcome! [We can't do this alone](//github.com/almende/vis/blob/master/misc/we_need_help.md). + +### Questions +If you have any *general question* on how to use the vis.js library in your own project please check out [stackoverflow](http://stackoverflow.com/questions/tagged/vis.js) for thinks like that. **This is NOT a JavaScript help forum!** + +### Bugs, Problems and Feature-Requests +If you really want to open a new issue: +* Please use the [search functionality](//github.com/almende/vis/issues) to make sure that there is not already an issue concerning the same topic. +* Please make sure to **mention which module** of vis.js (network, timeline, graph3d, ...) your are referring to. +* If you think you found a bug please **provide a simple example** (e.g. on [jsbin](jsbin.com)) that demonstrates the problem. +* If you want to propose a feature-request please **describe what you are looking for in detail**, ideally providing a screenshot, drawing or something similar. +* **Close the issue later**, when the issue is no longer needed. diff --git a/misc/how_to_help.md b/misc/how_to_help.md new file mode 100644 index 00000000..fe16e1e6 --- /dev/null +++ b/misc/how_to_help.md @@ -0,0 +1,67 @@ +# HowTo Help + +The company that developed vis.js for the main part, *almende* is [not able to maintain the project at the moment](./we_need_help.md). So help from the community is very needed and welcome! + +## There are many ways to help: + +### Answering questions + +There are new [issues with questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion+sort%3Acreated-desc) how to use vis.js opened almost every day. Be part of the community and help answer them! + +A better way to ask questions on how to use vis.js is [stackoverflow](https://stackoverflow.com/tags/vis.js). Questions are posed here also and need to be answered by the community. [Please help answering questions](https://stackoverflow.com/tags/vis.js) here also. + +### Closing old issues + +A new issue is often opened fast and then forgotten. Please help go trough [the old issues](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc) (especially the [questions](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc+label%3Aquestion)) and ask the creator of the issues if the problem still exists before closing the issue. The support team uses the **issue inactive** label to mark these issues. + +### Improve the webpage + +The visjs.org webpage is hosted on the [gh-pages branch](//github.com/almende/vis/tree/gh-pages). If you find a typo or anything else that should be improved feel free to create a pull-request to *gh-pages*. Please make changes in your own fork of gh-pages so the support team can view the changes in your hosted fork. + +### Create new examples + +We have [a collection of examples](//github.com/almende/vis/tree/develop/examples). Please help by creating interesting new ones that show a specific problem or layout. Keep the examples easy to understand for beginners and remove unnecessary clutter. + +### Provide interesting showcases + +If you use vis.js to develop something beautiful feel free to create a pull-request to our show cases page in the gh-pages branch](//github.com/almende/vis/tree/gh-pages/showcase). [These showcases are displayed on our webpage](http://visjs.org/showcase/index.html) and we are always looking for new examples. + +### Confirming and fixing bugs + +Every software has bugs. We also have [quite a nice collection](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) ;-) +Feel free to fix as many bugs as you want! + +You can not only help by fixing bugs, but also by confirming the bug or even creating a minimal code example to prove this bug exists. + +### Implementing Feature-Requests + +A lot of people have a lot of ideas for improving vis.js. [We label these issues as **enhancement**](https://github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement). Feel free to implement a new feature by creating a new Pull-Request. + +[Some issues are labeled **For everybody!**](//github.com/almende/vis/issues?q=is%3Aissue+is%3Aopen+label%3A%22For+everyone%21%22+sort%3Areactions-%2B1-desc). These are a good starting point. + +### Reviewing Pull-Requests + +We use [GitHub's two-step review](//help.github.com/articles/about-pull-request-reviews/) to make sure pull-requests are clean. You can help by checking out pull-request branches and testing them. You also can comment on lines of code and make sure the pull-request introduces no new bugs or typos. + +## Creating Pull Requests + +There are some rules for pull-request: + +* All pull-request must be to the [develop-branch](//github.com/almende/vis/tree/develop). Pull-request against the [master-branch](//github.com/almende/vis/tree/master) must be closed. (Changes to [gh-pages](//github.com/almende/vis/tree/gh-pages) are also ok.) + +* Only commit changes done in the source files in the folder `lib`, not to the builds + which are located in the folder `dist`. + +* Keep your changes small and clear. Only work on one topic at one time and only change lines of code that you have to change to reach your goal. + +* Test your changes before creating a pull-request. The easiest way is to open the existing examples and playing with them. + +* If you are fixing or implementing an existing issue, please refer to it in the description and in the commit message. + +* If you are introducing a new feature, add some documentation and a new example to make it easy to adapt. + +* If you introduce breaking changes, like changing the signature of a public function, point that out in your description. Breaking changes result in a new major release. + +* Always adapt to the code style of the existing source. Never adapt existing code to your personal taste. :trollface: + +**Happy Helping!!** diff --git a/misc/we_need_help.md b/misc/we_need_help.md new file mode 100644 index 00000000..fab2c431 --- /dev/null +++ b/misc/we_need_help.md @@ -0,0 +1,15 @@ +# We need help! + +## The current status + +Vis.js is looking for people who can help maintain and improve the library. We've put a lot of effort in building these visualizations, fixing bugs, and supporting users as much as we can. For some time now, we’ve been lacking the manpower to maintain the library the way we have in recent years. @josdejong has left the company for a new opportunity, and @AlexDM0 has moved internally to a daughter company, with severe impact on his time and availability for Vis.js. At the moment @ludost is the official maintainer from Almende, but does not have much time to help out. + +Although Almende is looking to replace the expertise required for Vis.js, we don't expect to be able to do comprehensive project management any time soon. At the same time we’d like to spare Vis.js from becoming abandonware, especially given the relative healthy user base. For the longer term future we would be happy if vis.js could stand on its own feet, community supported. + +**If you want to support the project please just start by [helping out](./how_to_help.md).** + +If you have shown some commitment to the project you can ask @ludost to become a member of the community support team. This team has write permissions to the repository and is helping maintaining it. Currently this team consists of: + +* @ludost (almende maintainer) +* @mojoaxel +* @yotamberk From f3e564311954512cd71898c796c5eb3b9e16aadd Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Wed, 19 Oct 2016 10:00:38 +0200 Subject: [PATCH 33/43] Added handling of settings for camera --- lib/graph3d/Graph3d.js | 94 ++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 61a6cdf6..08ccd6bb 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -98,6 +98,12 @@ var DEFAULTS = { fill : '#7DC1FF', stroke : '#3267D2', strokeWidth: 1 // px + }, + + cameraPosition : { + horizontal: 1.0, + vertical : 0.5, + distance : 1.7 } }; @@ -197,10 +203,6 @@ function Graph3d(container, data, options) { this.style = Graph3d.STYLE.DOT; - - this.camera = new Camera(); - this.camera.setArmRotation(1.0, 0.5); - this.camera.setArmLength(1.7); this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? // the column indexes @@ -396,12 +398,12 @@ Graph3d.prototype._calcTranslations = function(points, sort) { * 'Special' here means: setting requires more than a simple copy */ Graph3d.prototype._setSpecialSettings = function(src, dst) { - if (src.backgroundColor !== undefined) { this._setBackgroundColor(src.backgroundColor, dst); } this._setDataColor(src.dataColor, dst); + this._setCameraPosition(src.cameraPosition, dst); /* TODO setStyle(src.style, dst); @@ -410,11 +412,12 @@ Graph3d.prototype._setSpecialSettings = function(src, dst) { dst.showTooltip = src.tooltip; } - setCameraPosition(src.cameraPosition, dst); End TODO */ } + + /** * Set the background styling for the graph * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor @@ -472,6 +475,47 @@ Graph3d.prototype._setDataColor = function(dataColor, dst) { } +Graph3d.prototype._setCameraPosition = function(cameraPosition, dst) { + var camPos = cameraPosition; + if (camPos === undefined) { + return; + } + + if (dst.camera === undefined) { + dst.camera = new Camera(); + } + + dst.camera.setArmRotation(camPos.horizontal, camPos.vertical); + dst.camera.setArmLength(camPos.distance); +}; + + +// +// Public methods for specific settings +// + +/** + * Set the rotation and distance of the camera + * @param {Object} pos An object with the camera position. The object + * contains three parameters: + * - horizontal {Number} + * The horizontal rotation, between 0 and 2*PI. + * Optional, can be left undefined. + * - vertical {Number} + * The vertical rotation, between 0 and 0.5*PI + * if vertical=0.5*PI, the graph is shown from the + * top. Optional, can be left undefined. + * - distance {Number} + * The (normalized) distance of the camera to the + * center of the graph, a value between 0.71 and 5.0. + * Optional, can be left undefined. + */ +Graph3d.prototype.setCameraPosition = function(pos) { + this._setCameraPosition(pos, this); + this.redraw(); +}; + + // ----------------------------------------------------------------------------- // End methods for handling settings // ----------------------------------------------------------------------------- @@ -964,37 +1008,6 @@ Graph3d.prototype._resizeCenter = function() { } }; -/** - * Set the rotation and distance of the camera - * @param {Object} pos An object with the camera position. The object - * contains three parameters: - * - horizontal {Number} - * The horizontal rotation, between 0 and 2*PI. - * Optional, can be left undefined. - * - vertical {Number} - * The vertical rotation, between 0 and 0.5*PI - * if vertical=0.5*PI, the graph is shown from the - * top. Optional, can be left undefined. - * - distance {Number} - * The (normalized) distance of the camera to the - * center of the graph, a value between 0.71 and 5.0. - * Optional, can be left undefined. - */ -Graph3d.prototype.setCameraPosition = function(pos) { - if (pos === undefined) { - return; - } - - if (pos.horizontal !== undefined && pos.vertical !== undefined) { - this.camera.setArmRotation(pos.horizontal, pos.vertical); - } - - if (pos.distance !== undefined) { - this.camera.setArmLength(pos.distance); - } - - this.redraw(); -}; /** @@ -1085,13 +1098,6 @@ Graph3d.prototype.setOptions = function (options) { if (options.zMax !== undefined) this.defaultZMax = options.zMax; if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin; if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax; - - if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition; - - if (cameraPosition !== undefined) { - this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical); - this.camera.setArmLength(cameraPosition.distance); - } } this.setSize(this.width, this.height); From 832e9633753d9bc8ca7c9abd589b27311232d916 Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Wed, 19 Oct 2016 10:21:37 +0200 Subject: [PATCH 34/43] linked users to there profile --- misc/we_need_help.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/misc/we_need_help.md b/misc/we_need_help.md index fab2c431..a3eb9106 100644 --- a/misc/we_need_help.md +++ b/misc/we_need_help.md @@ -2,14 +2,14 @@ ## The current status -Vis.js is looking for people who can help maintain and improve the library. We've put a lot of effort in building these visualizations, fixing bugs, and supporting users as much as we can. For some time now, we’ve been lacking the manpower to maintain the library the way we have in recent years. @josdejong has left the company for a new opportunity, and @AlexDM0 has moved internally to a daughter company, with severe impact on his time and availability for Vis.js. At the moment @ludost is the official maintainer from Almende, but does not have much time to help out. +Vis.js is looking for people who can help maintain and improve the library. We've put a lot of effort in building these visualizations, fixing bugs, and supporting users as much as we can. For some time now, we’ve been lacking the manpower to maintain the library the way we have in recent years. [@josdejong](//github.com/josdejong) has left the company for a new opportunity, and [@AlexDM0](//github.com/AlexDM0) has moved internally to a daughter company, with severe impact on his time and availability for Vis.js. At the moment [@ludost](//github.com/ludost) is the official maintainer from Almende, but does not have much time to help out. Although Almende is looking to replace the expertise required for Vis.js, we don't expect to be able to do comprehensive project management any time soon. At the same time we’d like to spare Vis.js from becoming abandonware, especially given the relative healthy user base. For the longer term future we would be happy if vis.js could stand on its own feet, community supported. **If you want to support the project please just start by [helping out](./how_to_help.md).** -If you have shown some commitment to the project you can ask @ludost to become a member of the community support team. This team has write permissions to the repository and is helping maintaining it. Currently this team consists of: +If you have shown some commitment to the project you can ask [@ludost](//github.com/ludost) to become a member of the community support team. This team has write permissions to the repository and is helping maintaining it. Currently this team consists of: -* @ludost (almende maintainer) -* @mojoaxel -* @yotamberk +* [@ludost](//github.com/ludost) (almende maintainer) +* [@mojoaxel](//github.com/mojoaxel) +* [@yotamberk](//github.com/yotamberk) From bb627c66e66365473a9f7243a15b195acea446fd Mon Sep 17 00:00:00 2001 From: Uli Fahrer Date: Wed, 19 Oct 2016 11:27:04 +0200 Subject: [PATCH 35/43] Add Italian support for timeline --- docs/timeline/index.html | 8 ++++++++ examples/timeline/other/localization.html | 1 + lib/timeline/locales.js | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/docs/timeline/index.html b/docs/timeline/index.html index f32ac2a2..cd02f3d2 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -1715,6 +1715,14 @@ var options = { en_US + + Italian + + it
+ it_IT
+ it_CH + + Dutch diff --git a/examples/timeline/other/localization.html b/examples/timeline/other/localization.html index 4a05abad..ee1beeea 100644 --- a/examples/timeline/other/localization.html +++ b/examples/timeline/other/localization.html @@ -24,6 +24,7 @@

diff --git a/lib/timeline/locales.js b/lib/timeline/locales.js index fade73eb..50cbe03b 100644 --- a/lib/timeline/locales.js +++ b/lib/timeline/locales.js @@ -6,6 +6,12 @@ exports['en'] = { exports['en_EN'] = exports['en']; exports['en_US'] = exports['en']; +// Italiano +exports['it'] = { + current: 'attuale', + time: 'tempo' +}; + // Dutch exports['nl'] = { current: 'huidige', From 9a028a8634a2b7e2e0a835de9b44166f533a1015 Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Wed, 19 Oct 2016 12:50:48 +0200 Subject: [PATCH 36/43] Added step to defaults; fixes to detect and survive inconstent data --- lib/graph3d/Graph3d.js | 135 +++++++++++++++++++++++++++----------- lib/graph3d/StepNumber.js | 21 ++++++ 2 files changed, 119 insertions(+), 37 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 08ccd6bb..273d6cf8 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -12,6 +12,21 @@ var StepNumber = require('./StepNumber'); // Definitions private to module // ----------------------------------------------------------------------------- +/// enumerate the available styles +var STYLE = { + BAR : 0, + BARCOLOR: 1, + BARSIZE : 2, + DOT : 3, + DOTLINE : 4, + DOTCOLOR: 5, + DOTSIZE : 6, + GRID : 7, + LINE : 8, + SURFACE : 9 +}; + + /** * Field names in the options hash which are of relevance to the user. * @@ -32,9 +47,9 @@ var OPTIONKEYS = [ 'showGrid', 'showPerspective', 'showShadow', - 'showAnimationControls', 'keepAspectRatio', 'verticalRatio', + 'showAnimationControls', 'animationInterval', 'animationPreload', 'animationAutoStart', @@ -76,28 +91,28 @@ var DEFAULTS = { showPerspective : true, showShadow : false, keepAspectRatio : true, - verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube' - animationInterval: 1000, // milliseconds - animationPreload : false, + verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube' + + showAnimationControls: undefined, // auto by default + animationInterval : 1000, // milliseconds + animationPreload : false, + animationAutoStart : undefined, // auto by default + axisColor : '#4D4D4D', gridColor : '#D3D3D3', xCenter : '55%', yCenter : '50%', - // Following not in defaults (yet) but present in user settings - // These will be initialized as 'undefined' - //'showAnimationControls', - //'animationAutoStart' - // Following not in OPTIONKEYS because they require special handling, + style : STYLE.DOT, // Can't use Graph3d.STYLE here, not defined yet backgroundColor : undefined, dataColor : { fill : '#7DC1FF', stroke : '#3267D2', - strokeWidth: 1 // px + strokeWidth: 1 // px }, cameraPosition : { @@ -154,6 +169,15 @@ function safeCopy(src, dst, fields) { // Class Graph3d // ----------------------------------------------------------------------------- +/** + * Enumerate the available styles. + * + * This definition retained for external compatibility + * (It should be internal, but you never know) + */ +Graph3d.STYLE = STYLE; + + /** * @constructor Graph3d * Graph3d displays data in 3d. @@ -201,8 +225,6 @@ function Graph3d(container, data, options) { this.showLegend = undefined; // auto by default (based on graph style) - this.style = Graph3d.STYLE.DOT; - this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? // the column indexes @@ -403,10 +425,10 @@ Graph3d.prototype._setSpecialSettings = function(src, dst) { } this._setDataColor(src.dataColor, dst); + this._setStyle(src.style, dst); this._setCameraPosition(src.cameraPosition, dst); /* TODO - setStyle(src.style, dst); if (src.tooltip !== undefined) { dst.showTooltip = src.tooltip; @@ -416,6 +438,39 @@ End TODO */ } +Graph3d.prototype._setStyle = function(style, dst) { + if (style === undefined) { + return; // Nothing to do + } + + var styleNumber; + + if (typeof style === 'string') { + styleNumber = this._getStyleNumber(style); + + if (styleNumber === -1 ) { + throw new Error('Style \'' + style + '\' is invalid'); + } + } else { + // Do a pedantic check on style number value + var valid = false; + for (var n in STYLE) { + if (STYLE[n] === style) { + valid = true; + break; + } + } + + if (!valid) { + throw new Error('Style \'' + style + '\' is invalid'); + } + + styleNumber = style; + } + + dst.style = styleNumber; +} + /** @@ -521,19 +576,7 @@ Graph3d.prototype.setCameraPosition = function(pos) { // ----------------------------------------------------------------------------- -/// enumerate the available styles -Graph3d.STYLE = { - BAR: 0, - BARCOLOR: 1, - BARSIZE: 2, - DOT : 3, - DOTLINE : 4, - DOTCOLOR: 5, - DOTSIZE: 6, - GRID : 7, - LINE: 8, - SURFACE : 9 -}; + /** * Retrieve the style index from given styleName @@ -686,13 +729,11 @@ Graph3d.prototype._dataInitialize = function (rawData, style) { this.colX = 'x'; this.colY = 'y'; this.colZ = 'z'; - this.colValue = 'style'; - this.colFilter = 'filter'; - - // check if a filter column is provided if (data[0].hasOwnProperty('filter')) { + this.colFilter = 'filter'; // Bugfix: only set this field if it's actually present! + if (this.dataFilter === undefined) { this.dataFilter = new Filter(rawData, this.colFilter, this); this.dataFilter.setOnLoadCallback(function() {me.redraw();}); @@ -750,7 +791,9 @@ Graph3d.prototype._dataInitialize = function (rawData, style) { if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; - if (this.colValue !== undefined) { + // Bugfix: Only handle field 'style' if it's actually present + if (data[0].hasOwnProperty('style')) { + this.colValue = 'style'; var valueRange = this.getColumnRange(data,this.colValue); this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min; this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; @@ -850,6 +893,30 @@ Graph3d.prototype._getDataPoints = function (data) { } } else { // 'dot', 'dot-line', etc. + + // Bugfix: ensure value field is present in data if expected + var hasValueField = this.style === Graph3d.STYLE.BARCOLOR + || this.style === Graph3d.STYLE.BARSIZE + || this.style === Graph3d.STYLE.DOTCOLOR + || this.style === Graph3d.STYLE.DOTSIZE; + + if (hasValueField) { + if (this.colValue === undefined) { + throw new Error('Expected data to have ' + + ' field \'style\' ' + + ' for graph style \'' + this.style + '\'' + ); + } + + if (data[0][this.colValue] === undefined) { + throw new Error('Expected data to have ' + + ' field \'' + this.colValue + '\' ' + + ' for graph style \'' + this.style + '\'' + ); + } + } + + // copy all values from the google data table to a list with Point3d objects for (i = 0; i < data.length; i++) { point = new Point3d(); @@ -1077,12 +1144,6 @@ Graph3d.prototype.setOptions = function (options) { // Handle the rest of the parameters if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; - if (options.style !== undefined) { - var styleNumber = this._getStyleNumber(options.style); - if (styleNumber !== -1) { - this.style = styleNumber; - } - } if (options.tooltip !== undefined) this.showTooltip = options.tooltip; if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; diff --git a/lib/graph3d/StepNumber.js b/lib/graph3d/StepNumber.js index 72a73839..9675b4f8 100644 --- a/lib/graph3d/StepNumber.js +++ b/lib/graph3d/StepNumber.js @@ -35,6 +35,17 @@ function StepNumber(start, end, step, prettyStep) { this.setRange(start, end, step, prettyStep); }; + +/** + * Check for input values, to prevent disasters from happening + * + * Source: http://stackoverflow.com/a/1830844 + */ +StepNumber.prototype.isNumeric = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +}; + + /** * Set a new range: start, end and step. * @@ -45,6 +56,16 @@ function StepNumber(start, end, step, prettyStep) { * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) */ StepNumber.prototype.setRange = function(start, end, step, prettyStep) { + if (!this.isNumeric(start)) { + throw new Error('Parameter \'start\' is not numeric; value: ' + start); + } + if (!this.isNumeric(end)) { + throw new Error('Parameter \'end\' is not numeric; value: ' + start); + } + if (!this.isNumeric(step)) { + throw new Error('Parameter \'step\' is not numeric; value: ' + start); + } + this._start = start ? start : 0; this._end = end ? end : 0; From e6351b63bdd8e9dd9db72bfba89fe001c47060bf Mon Sep 17 00:00:00 2001 From: Wim Rijnders Date: Wed, 19 Oct 2016 13:32:31 +0200 Subject: [PATCH 37/43] Adjusted STYLE enum to previous --- lib/graph3d/Graph3d.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 273d6cf8..fbb909cb 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -13,7 +13,7 @@ var StepNumber = require('./StepNumber'); // ----------------------------------------------------------------------------- /// enumerate the available styles -var STYLE = { +Graph3d.STYLE = { BAR : 0, BARCOLOR: 1, BARSIZE : 2, @@ -106,7 +106,7 @@ var DEFAULTS = { // Following not in OPTIONKEYS because they require special handling, - style : STYLE.DOT, // Can't use Graph3d.STYLE here, not defined yet + style : Graph3d.STYLE.DOT, backgroundColor : undefined, dataColor : { @@ -169,14 +169,6 @@ function safeCopy(src, dst, fields) { // Class Graph3d // ----------------------------------------------------------------------------- -/** - * Enumerate the available styles. - * - * This definition retained for external compatibility - * (It should be internal, but you never know) - */ -Graph3d.STYLE = STYLE; - /** * @constructor Graph3d @@ -454,8 +446,8 @@ Graph3d.prototype._setStyle = function(style, dst) { } else { // Do a pedantic check on style number value var valid = false; - for (var n in STYLE) { - if (STYLE[n] === style) { + for (var n in Graph3d.STYLE) { + if (Graph3d.STYLE[n] === style) { valid = true; break; } From 51f0db9d287b80fbbd3cb9093618da5d44c652cd Mon Sep 17 00:00:00 2001 From: Uli Fahrer Date: Wed, 19 Oct 2016 13:46:45 +0200 Subject: [PATCH 38/43] Add Italian locale support for network (#2184) Thanks @federicoco for providing the translation! --- docs/network/index.html | 2 +- lib/network/locales.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/network/index.html b/docs/network/index.html index 60d0dd47..69f09644 100644 --- a/docs/network/index.html +++ b/docs/network/index.html @@ -336,7 +336,7 @@ network.setOptions(options); locales Object defaultLocales - Locales object. By default only 'en', 'de', 'es' and 'nl' are supported. Take a look + Locales object. By default only 'en', 'de', 'es', 'it' and 'nl' are supported. Take a look at the locales diff --git a/lib/network/locales.js b/lib/network/locales.js index ad5a523a..e71a971f 100644 --- a/lib/network/locales.js +++ b/lib/network/locales.js @@ -53,6 +53,24 @@ exports['es'] = { }; exports['es_ES'] = exports['es']; +//Italiano +exports['it'] = { + edit: 'Modifica', + del: 'Cancella la selezione', + back: 'Indietro', + addNode: 'Aggiungi un nodo', + addEdge: 'Aggiungi un vertice', + editNode: 'Modifica il nodo', + editEdge: 'Modifica il vertice', + addDescription: 'Clicca per aggiungere un nuovo nodo', + edgeDescription: 'Clicca su un nodo e trascinalo ad un altro nodo per connetterli.', + editEdgeDescription: 'Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.', + createEdgeError: 'Non si possono collegare vertici ad un cluster', + deleteClusterError: 'I cluster non possono essere cancellati', + editClusterError: 'I clusters non possono essere modificati.' +}; +exports['it_IT'] = exports['it']; + // Dutch exports['nl'] = { edit: 'Wijzigen', From f61c83ac6e8eaaf833fcccd7a05dc21fece1eb0a Mon Sep 17 00:00:00 2001 From: Alexander Wunschik Date: Wed, 19 Oct 2016 14:36:45 +0200 Subject: [PATCH 39/43] cleaned up locale; added all locals to example; set users local as default --- docs/network/index.html | 22 +++++++++++-------- examples/network/other/manipulation.html | 27 +++++++++++++++++++++--- lib/network/options.js | 6 ------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/docs/network/index.html b/docs/network/index.html index 69f09644..cfd03d64 100644 --- a/docs/network/index.html +++ b/docs/network/index.html @@ -328,19 +328,23 @@ network.setOptions(options); locale String 'en' - Select the locale. By default, the language is English. If you want to use another language, you - will - need to define your own locale and refer to it here. + Select the locale. By default, the language is English. locales Object defaultLocales - Locales object. By default only 'en', 'de', 'es', 'it' and 'nl' are supported. Take a look - at - the locales - section below for more explaination on how to customize this. + Locales object. By default + 'en', + 'de', + 'es', + 'it', + 'nl' + 'pt-br', + 'ru' + are supported. Take a look at the + locales section below + for more explaination on how to customize this. clickToUse @@ -998,7 +1002,7 @@ function releaseFunction (clusterPosition, containedNodesPositions) { setSelection( - Object selection, + Object selection, [Object options]) diff --git a/examples/network/other/manipulation.html b/examples/network/other/manipulation.html index c97dacb3..b399c098 100644 --- a/examples/network/other/manipulation.html +++ b/examples/network/other/manipulation.html @@ -1,6 +1,7 @@ + Network | Manipulation