From d51be3bbf57b2420bcb549ae8e2da8bf7ba20558 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:32:47 +0200 Subject: [PATCH 1/6] Delegate the onRender function to the correct property --- lib/timeline/Core.js | 7 +++++++ lib/timeline/component/GraphGroup.js | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/lib/timeline/Core.js b/lib/timeline/Core.js index 4000dd96..5d81ffe6 100644 --- a/lib/timeline/Core.js +++ b/lib/timeline/Core.js @@ -254,6 +254,13 @@ Core.prototype.setOptions = function (options) { } } + // if the graph2d's drawPoints is a function delegate the callback to the onRender property + if (typeof options.drawPoints == 'function') { + options.drawPoints = { + onRender: options.drawPoints + }; + } + if ('hiddenDates' in this.options) { DateUtil.convertHiddenOptions(this.body, this.options.hiddenDates); } diff --git a/lib/timeline/component/GraphGroup.js b/lib/timeline/component/GraphGroup.js index 284fae51..0e62747f 100644 --- a/lib/timeline/component/GraphGroup.js +++ b/lib/timeline/component/GraphGroup.js @@ -69,6 +69,13 @@ GraphGroup.prototype.setOptions = function(options) { var fields = ['sampling','style','sort','yAxisOrientation','barChart']; util.selectiveDeepExtend(fields, this.options, options); + // if the group's drawPoints is a function delegate the callback to the onRender property + if (typeof options.drawPoints == 'function') { + options.drawPoints = { + onRender: options.drawPoints + } + } + util.mergeOptions(this.options, options,'interpolation'); util.mergeOptions(this.options, options,'drawPoints'); util.mergeOptions(this.options, options,'shaded'); From 71f875f8fd026e9570ae31d9f502d3c6505695b2 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:33:52 +0200 Subject: [PATCH 2/6] added onRender as a drawPoints property and as a function on the object itself --- lib/timeline/optionsGraph2d.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/timeline/optionsGraph2d.js b/lib/timeline/optionsGraph2d.js index df172ed4..40569248 100644 --- a/lib/timeline/optionsGraph2d.js +++ b/lib/timeline/optionsGraph2d.js @@ -51,9 +51,10 @@ let allOptions = { }, drawPoints: { enabled: {boolean}, + onRender: { 'function': 'function' }, size: {number}, style: {string:['square','circle']}, // square, circle - __type__: {object,boolean} + __type__: {object,boolean,'function': 'function'} }, dataAxis: { showMinorLabels: {boolean}, From f39c246e5cd617348a045d65001a56aabe108170 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:35:44 +0200 Subject: [PATCH 3/6] Updated Points.draw method to support onRender + Checking for callbacks + Using the newly generated 'groupTemplate' object instead of group + Updated calls to DOMutil.drawPoint to use the groupTemplate instead of group --- lib/DOMutil.js | 30 +++++++------- lib/timeline/component/GraphGroup.js | 7 +++- .../component/graph2d_types/points.js | 39 ++++++++++++++++++- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/lib/DOMutil.js b/lib/DOMutil.js index ee4506d1..ebedeb21 100644 --- a/lib/DOMutil.js +++ b/lib/DOMutil.js @@ -121,43 +121,43 @@ exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, inse /** - * draw a point object. this is a seperate function because it can also be called by the legend. + * Draw a point object. This is a separate function because it can also be called by the legend. * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions * as well. * * @param x * @param y - * @param group + * @param groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' } * @param JSONcontainer * @param svgContainer * @param labelObj * @returns {*} */ -exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer, labelObj) { +exports.drawPoint = function(x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) { var point; - if (group.options.drawPoints.style == 'circle') { - point = exports.getSVGElement('circle',JSONcontainer,svgContainer); + if (groupTemplate.style == 'circle') { + point = exports.getSVGElement('circle', JSONcontainer, svgContainer); point.setAttributeNS(null, "cx", x); point.setAttributeNS(null, "cy", y); - point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size); + point.setAttributeNS(null, "r", 0.5 * groupTemplate.size); } else { - point = exports.getSVGElement('rect',JSONcontainer,svgContainer); - point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size); - point.setAttributeNS(null, "width", group.options.drawPoints.size); - point.setAttributeNS(null, "height", group.options.drawPoints.size); + point = exports.getSVGElement('rect', JSONcontainer, svgContainer); + point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size); + point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size); + point.setAttributeNS(null, "width", groupTemplate.size); + point.setAttributeNS(null, "height", groupTemplate.size); } - if(group.options.drawPoints.styles !== undefined) { - point.setAttributeNS(null, "style", group.group.options.drawPoints.styles); + if (groupTemplate.style !== undefined) { + point.setAttributeNS(null, "style", groupTemplate.style); } - point.setAttributeNS(null, "class", group.className + " vis-point"); + point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); //handle label if (labelObj) { - var label = exports.getSVGElement('text',JSONcontainer,svgContainer); + var label = exports.getSVGElement('text', JSONcontainer, svgContainer); if (labelObj.xOffset) { x = x + labelObj.xOffset; } diff --git a/lib/timeline/component/GraphGroup.js b/lib/timeline/component/GraphGroup.js index 0e62747f..0aac3316 100644 --- a/lib/timeline/component/GraphGroup.js +++ b/lib/timeline/component/GraphGroup.js @@ -169,7 +169,12 @@ GraphGroup.prototype.drawIcon = function(x, y, JSONcontainer, SVGcontainer, icon } if (this.options.drawPoints.enabled == true) { - DOMutil.drawPoint(x + 0.5 * iconWidth,y, this, JSONcontainer, SVGcontainer); + var groupTemplate = { + style: this.options.drawPoints.style, + size:this.options.drawPoints.size, + className: this.className + }; + DOMutil.drawPoint(x + 0.5 * iconWidth, y, groupTemplate, JSONcontainer, SVGcontainer); } } else { diff --git a/lib/timeline/component/graph2d_types/points.js b/lib/timeline/component/graph2d_types/points.js index 235026b5..4b18f0f2 100644 --- a/lib/timeline/component/graph2d_types/points.js +++ b/lib/timeline/component/graph2d_types/points.js @@ -30,10 +30,45 @@ Points.prototype.draw = function(dataset, group, framework, offset) { * @param {Number} [offset] */ Points.draw = function (dataset, group, framework, offset) { - if (offset === undefined) {offset = 0;} + offset = offset || 0; + var callback = getCallback(); + for (var i = 0; i < dataset.length; i++) { - DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, group, framework.svgElements, framework.svg, dataset[i].label); + if (!callback) { + // draw the point the simple way. + DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, getGroupTemplate(), framework.svgElements, framework.svg, dataset[i].label); + } else { + var callbackResult = callback(dataset[i], group, framework); // result might be true, false or an object + if (callbackResult === true || typeof callbackResult === 'object') { + DOMutil.drawPoint(dataset[i].x + offset, dataset[i].y, getGroupTemplate(callbackResult), framework.svgElements, framework.svg, dataset[i].label); + } + } + } + + function getGroupTemplate(callbackResult) { + callbackResult = (typeof callbackResult === 'undefined') ? {} : callbackResult; + return { + style: callbackResult.style || group.options.drawPoints.style, + size: callbackResult.size || group.options.drawPoints.size, + className: callbackResult.className || group.className + }; } + + function getCallback() { + var callback = undefined; + // check for the graph2d onRender + if (framework.options.drawPoints.onRender && typeof framework.options.drawPoints.onRender == 'function') { + callback = framework.options.drawPoints.onRender; + } + + // override it with the group onRender if defined + if (group.group.options && group.group.options.drawPoints && group.group.options.drawPoints.onRender && typeof group.group.options.drawPoints.onRender == 'function') { + callback = group.group.options.drawPoints.onRender; + } + + return callback; + } +}; }; From 06b78a0580b056dc0f978c6e89c392a6173e5278 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:39:42 +0200 Subject: [PATCH 4/6] Updated example 19_labels.html --- examples/graph2d/19_labels.html | 92 +++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/examples/graph2d/19_labels.html b/examples/graph2d/19_labels.html index b39f6c2d..6fd102bf 100644 --- a/examples/graph2d/19_labels.html +++ b/examples/graph2d/19_labels.html @@ -35,31 +35,101 @@ var container = document.getElementById('visualization'); var label1 = { - content: "offset label", + content: "Label 1 (with offset)", xOffset: 20, yOffset: 20 } var label2 = { - content: "Label2", + content: "Label 2", className: "red" } + + var label3 = { + content: "Label 3" + } var items = [ - {x: '2014-06-11', y: 10,label:label1}, - {x: '2014-06-12', y: 25,label:label2}, - {x: '2014-06-13', y: 30}, - {x: '2014-06-14', y: 10}, - {x: '2014-06-15', y: 15}, - {x: '2014-06-16', y: 30} + {group: 1, x: '2014-06-11', y: 10, label: label1}, + {group: 1, x: '2014-06-12', y: 25, label: label2}, + {group: 1, x: '2014-06-13', y: 30}, + {group: 1, x: '2014-06-14', y: 10}, + {group: 1, x: '2014-06-15', y: 15, label: label3}, + {group: 1, x: '2014-06-16', y: 30}, + + {group: 2, x: '2014-06-17', y: 10, label:label1}, + {group: 2, x: '2014-06-18', y: 25, label:label2}, + {group: 2, x: '2014-06-19', y: 30}, + {group: 2, x: '2014-06-20', y: 10}, + {group: 2, x: '2014-06-21', y: 15, label: label3}, + {group: 2, x: '2014-06-22', y: 30}, + + {group: 3, x: '2014-06-23', y: 10, label:label1}, + {group: 3, x: '2014-06-24', y: 25, label:label2}, + {group: 3, x: '2014-06-25', y: 30}, + {group: 3, x: '2014-06-26', y: 10}, + {group: 3, x: '2014-06-27', y: 15, label: label3}, + {group: 3, x: '2014-06-28', y: 30} ]; + var groups = new vis.DataSet(); + groups.add( + { + id: 1, + content: "Only draw items with labels. Make the data point bigger and a square.", + options: { + drawPoints: function group1Renderer(item, group, grap2d) { + if (item.label == null) { + return false; + } + return { + style: 'square', + size: 15 + }; + } + } + } + ); + + groups.add( + { + id: 2, + content: "Draw according to the Graph2d callback, but make it every datapoint square one.", + options: { + drawPoints: { + style: 'square' + } + } + } + ); + + groups.add( + { + id: 3, + content: "I want to render datapoints with no labels. Screw the graph2d options. Except the style/size should be according to the graph2d option.", + options: { + drawPoints: function(item, group, grap2d) { + return item.label == null; + } + } + } + ); + var dataset = new vis.DataSet(items); var options = { start: '2014-06-10', - end: '2014-06-18', - style:'bar' + end: '2014-06-29', + style: 'bar', + drawPoints: { + onRender: function(item, group, grap2d) { + return item.label != null; + }, + style: 'circle' + } + }; - var graph2d = new vis.Graph2d(container, dataset, options); + + var graph2d = new vis.Graph2d(container, dataset, groups, options); + \ No newline at end of file From 35e8e15a178aad2a8d6567f13b7f78c0c0ff18a8 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:40:52 +0200 Subject: [PATCH 5/6] Updated graph2d docs for drawPoints & drawPoints.onRender --- docs/graph2d/index.html | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/docs/graph2d/index.html b/docs/graph2d/index.html index cf3fdfb7..20b54195 100644 --- a/docs/graph2d/index.html +++ b/docs/graph2d/index.html @@ -546,15 +546,73 @@ function (value) { drawPoints - Boolean or Object + Boolean, Object or Function true - Toggle the drawing of the datapoints with the default settings. + Defines rendering options for the datapoints. + Three different types of objects can be assigned to this property. See Example 19 for an illustration.
+ 1. Boolean: When true is provided every datapoint will be drawn, false otherwise.
+
+drawPoints: true // or false
+            
+ + 2. Object (the 'rendering' options): If an object is provided it may contain following properties which all can be optional: onRender, classNamesize and/or style. For more information check the property's documentation.
+
+drawPoints: {
+  size: 3,
+  style: 'square'
+}
+            
+ + 3. Function: If a function is provided it will be used as a callback. The function may return values from listing 1 or 2.
+
+drawPoints: function(item, group, graph2d) {
+  ...
+}
+            
+ If a rendering property from the rendering option object is missing, the missing property will be fetched from the group's option. +
+ All of these three options can be defined within the drawPoints properties separately as well. + drawPoints.enabled Boolean true - Toggle the drawing of the datapoints. + Toggles the drawing of the datapoints. + + + drawPoints.onRender + function + none + Defines a render function for every datapoint. + If a group has no drawPoints.onRender callback, the graph2d drawPoints.onRender callback will be used. + If neither is defined, the datapoint will be rendered according to the group setting of drawPoints.enabled. + This callback must return true if the datapoint should be rendered, otherwise false. +
+drawPoints: {
+  enabled: true,
+  onRender: function(item, group, graph2d) {
+    // only renders items with labels
+    return item.label != null;
+  }
+}
+              
+ This callback may also return an object containing a size and style property, both are optional, e.g.: +
+onRender: function(item, group, graph2d) {
+  if (item.label == null) {
+    return false;
+  }
+
+  return {
+    style: 'circle',
+    size: 30
+  };
+}
+              
+ The properties className, style and size returned from the callback will be used for rendering the datapoint. + If a property is missing in the rendering option object, the missing property will be fetched from the group's option. + drawPoints.size From 51e2135f53fbc40e9f6c02f11d71588b78749661 Mon Sep 17 00:00:00 2001 From: Manuel Schallar Date: Mon, 29 Jun 2015 11:46:09 +0200 Subject: [PATCH 6/6] Fixed multiple paths to examples --- docs/graph2d/index.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/graph2d/index.html b/docs/graph2d/index.html index 20b54195..10c4606e 100644 --- a/docs/graph2d/index.html +++ b/docs/graph2d/index.html @@ -158,7 +158,7 @@

The following code shows how to create a Graph2d and provide it with data. - More examples can be found in the examples directory.

+ More examples can be found in the examples directory.

 <!DOCTYPE HTML>
@@ -424,8 +424,8 @@ var options = {
             Boolean
             false
             If two datapoints of a barchart overlap, they are drawn over eachother by default. If sideBySide is set to true, they will be drawn side by side.
-                See example 10 for more information.
-                When using groups, see example 11.
+                See example 10 for more information.
+                When using groups, see example 11.
             
         
         
@@ -639,7 +639,7 @@ onRender: function(item, group, graph2d) {
             Object
             
             You can use this to toggle the visibility of groups per graph2D instance. This is different from setting the visibility flag of the groups since
-                this is not communicated across instances of graph2d. Take a look at Example 14
+                this is not communicated across instances of graph2d. Take a look at Example 14
                 for more explanation.
             
         
@@ -659,7 +659,7 @@ onRender: function(item, group, graph2d) {
             interpolation.parametrization
             String
             'centripetal'
-            Define the type of parametrizaion for the catmullRom interpolation. Example 7 shows the different parametrizations. The options are 'centripetal' (best results), 'chordal' and 'uniform'. Uniform is the computationally cheapest variant.
+            Define the type of parametrizaion for the catmullRom interpolation. Example 7 shows the different parametrizations. The options are 'centripetal' (best results), 'chordal' and 'uniform'. Uniform is the computationally cheapest variant.
                 If interpolation is disabled, linear interpolation is used.
         
         
@@ -758,7 +758,7 @@ onRender: function(item, group, graph2d) {
             yAxisOrientation
             String
             'left'
-            This defines with which axis, left or right, the graph is coupled. Example 5 shows groups with different Y axis. If no groups are coupled
+            This defines with which axis, left or right, the graph is coupled. Example 5 shows groups with different Y axis. If no groups are coupled
                 with an axis, it will not be shown.
         
     
@@ -1399,8 +1399,8 @@ Graph2d.off('rangechanged', onChange);
     

Additionally, Graph2d has 10 preset styles for graphs, which are cycled through when loading groups. These styles can be overwritten - as well, along with defining your own classes to style the graphs! Example 4 and - example 5 show the usage of custom styles. + as well, along with defining your own classes to style the graphs! Example 4 and + example 5 show the usage of custom styles.