diff --git a/docs/graph2d/index.html b/docs/graph2d/index.html index cf3fdfb7..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.
             
         
         
@@ -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 @@ -581,7 +639,7 @@ function (value) { 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. @@ -601,7 +659,7 @@ function (value) { 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. @@ -700,7 +758,7 @@ function (value) { 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. @@ -1341,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.

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 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/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..0aac3316 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'); @@ -162,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; + } +}; }; 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},