Browse Source

Added barChart overlap functions

v3_develop
Alex de Mulder 10 years ago
parent
commit
4ad7165bb7
10 changed files with 24295 additions and 23977 deletions
  1. +24016
    -23958
      dist/vis.js
  2. +1
    -1
      dist/vis.map
  3. +8
    -8
      dist/vis.min.js
  4. +47
    -0
      docs/graph2d.html
  5. +70
    -0
      examples/graph2d/10_barsSideBySide.html
  6. +82
    -0
      examples/graph2d/11_barsSideBySideGroups.html
  7. +3
    -0
      examples/graph2d/index.html
  8. +2
    -2
      lib/network/Node.js
  9. +2
    -2
      lib/timeline/component/GraphGroup.js
  10. +64
    -6
      lib/timeline/component/LineGraph.js

+ 24016
- 23958
dist/vis.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/vis.map
File diff suppressed because it is too large
View File


+ 8
- 8
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 47
- 0
docs/graph2d.html View File

@ -37,6 +37,7 @@
<ul> <ul>
<li><a href="#items">Items</a></li> <li><a href="#items">Items</a></li>
<li><a href="#groups">Groups</a></li> <li><a href="#groups">Groups</a></li>
<li><a href="#GroupOptions">Group-specific options</a></li>
</ul> </ul>
</li> </li>
<li><a href="#Configuration_Options">Configuration Options</a> <li><a href="#Configuration_Options">Configuration Options</a>
@ -250,6 +251,43 @@ groups.add({
</tr> </tr>
</table> </table>
<h3 id="GroupOptions">Group-specific Options</h3>
The groups have some options that only apply to groups and cannot be set globally. These are listed below.
<pre class="prettyprint lang-js">
var groups = new vis.DataSet();
groups.add({
id: 1,
content: 'Group 1',
options: {
slots: { slot: 1, total: 3}
}
});
</pre>
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>Required</th>
<th>Description</th>
</tr>
<tr>
<td>slots.slot</td>
<td>Number</td>
<td></td>
<td>The slot the bar chart is plotted in. This has to be used in combination with slots.total. See <a href="../examples/graph2d/11_barsSideBySideGroups.html">example 11</a> for more information.</td>
</tr>
<tr>
<td>slots.total</td>
<td>Number</td>
<td></td>
<td>The total amount of slots available. This has to be used in combination with slots.slot. See <a href="../examples/graph2d/11_barsSideBySideGroups.html">example 11</a> for more information.</td>
</tr>
</table>
<h2 id="Configuration_Options">Configuration Options</h2> <h2 id="Configuration_Options">Configuration Options</h2>
<h3 id="graph2dOptions">Graph2d Options</h3> <h3 id="graph2dOptions">Graph2d Options</h3>
@ -345,6 +383,15 @@ The options colored in green can also be used as options for the groups. All opt
<td>'center'</td> <td>'center'</td>
<td>The alignment of the bars with regards to the coordinate. The options are 'left', 'right' or 'center'.</td> <td>The alignment of the bars with regards to the coordinate. The options are 'left', 'right' or 'center'.</td>
</tr> </tr>
<tr>
<td class="greenField">barChart.allowOverlap</td>
<td>Boolean</td>
<td>true</td>
<td>When true, bars that have the same x coordinate are plotted on top of eachother (not stacking).
See <a href="../examples/graph2d/10_barsSideBySide.html">example 10</a> for more information.
When using groups, see <a href="../examples/graph2d/11_barsSideBySideGroups.html">example 11</a>.
</td>
</tr>
<tr> <tr>
<td class="greenField">catmullRom</td> <td class="greenField">catmullRom</td>
<td>Boolean | Object</td> <td>Boolean | Object</td>

+ 70
- 0
examples/graph2d/10_barsSideBySide.html View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Graph2d | Bar Graph Example</title>
<style type="text/css">
body, html {
font-family: sans-serif;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h2>Graph2d | Bar Graphs Side by Side Example</h2>
<div style="width:700px; font-size:14px; text-align: justify;">
When using Bar graphs, it can often be the case that there are multiple bars on the same timepoint. This may not always be the desired result. If you're not using groups, you can use the
barChart.allowOverlap option to automatically plot the bars next to eachother if they occupy the same timeslot. By default, this option is on, making the bars overlap. If the option is disabled, the overlapping
bars are plotted side by side. Use the toggle below to switch between settings.
<br /><br />
Allow overlap: <input type="checkbox" id="allowOverlap" checked="checked">
</div>
<br />
<div id="visualization"></div>
<script type="text/javascript">
var container = document.getElementById('visualization');
var checkbox = document.getElementById('allowOverlap');
var items = [
{x: '2014-06-11', y: 10},
{x: '2014-06-12', y: 25},
{x: '2014-06-13', y: 30},
{x: '2014-06-14', y: 10},
{x: '2014-06-15', y: 15},
{x: '2014-06-16', y: 30},
{x: '2014-06-11', y: 12},
{x: '2014-06-14', y: 24},
{x: '2014-06-15', y: 5},
{x: '2014-06-16', y: 12}
];
var dataset = new vis.DataSet(items);
var options = {
style:'bar',
barChart: {width:50, align:'center'}, // align: left, center, right
drawPoints: false,
dataAxis: {
icons:true
},
orientation:'top',
start: '2014-06-10',
end: '2014-06-18'
};
var graph2d = new vis.Graph2d(container, items, options);
checkbox.onchange = toggleOption;
function toggleOption() {
var options = {barChart:{allowOverlap:checkbox.checked}};
graph2d.setOptions(options);
}
</script>
</body>
</html>

+ 82
- 0
examples/graph2d/11_barsSideBySideGroups.html View File

@ -0,0 +1,82 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Graph2d | Bar Graph Example</title>
<style type="text/css">
body, html {
font-family: sans-serif;
}
</style>
<script src="../../dist/vis.js"></script>
<link href="../../dist/vis.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h2>Graph2d | Bar Graphs Side by Side Example</h2>
<div style="width:700px; font-size:14px; text-align: justify;">
When using Bar graphs, it can often be the case that there are multiple bars on the same timepoint. This may not always be the desired result. Since groups are plotted one at a time, the allowOverlap option does
not work here. For groups you can use the "slots" option.
<pre class="prettyprint lang-js">
var options = {
slots: {
slot: 1,
total:3
}
};
</pre>
<br /><br />
The slots tell the group where to plot it's bar. Each group is given a slot and the total amount of slots. Using this, the bars are plotted side by side neatly.
</div>
<br />
<div id="visualization"></div>
<script type="text/javascript">
var container = document.getElementById('visualization');
var groups = new vis.DataSet();
groups.add({id: 0, content: "group0", options: {slots:{slot:1,total:3}}})
groups.add({id: 1, content: "group1", options: {slots:{slot:2,total:3}}})
groups.add({id: 2, content: "group2", options: {slots:{slot:3,total:3}}})
var items = [
{x: '2014-06-11', y: 10, group:0},
{x: '2014-06-12', y: 25, group:0},
{x: '2014-06-13', y: 30, group:0},
{x: '2014-06-14', y: 10, group:0},
{x: '2014-06-15', y: 15, group:0},
{x: '2014-06-16', y: 30, group:0},
{x: '2014-06-11', y: 12, group:1},
{x: '2014-06-12', y: 15, group:1},
{x: '2014-06-13', y: 34, group:1},
{x: '2014-06-14', y: 24, group:1},
{x: '2014-06-15', y: 5, group:1},
{x: '2014-06-16', y: 12, group:1},
{x: '2014-06-11', y: 22, group:2},
{x: '2014-06-12', y: 14, group:2},
{x: '2014-06-13', y: 24, group:2},
{x: '2014-06-14', y: 21, group:2},
{x: '2014-06-15', y: 30, group:2},
{x: '2014-06-16', y: 18, group:2}
];
var dataset = new vis.DataSet(items);
var options = {
style:'bar',
barChart: {width:50, align:'center'}, // align: left, center, right
drawPoints: false,
dataAxis: {
icons:true
},
orientation:'top',
start: '2014-06-10',
end: '2014-06-18'
};
var graph2d = new vis.Graph2d(container, items, options,groups);
</script>
</body>
</html>

+ 3
- 0
examples/graph2d/index.html View File

@ -15,6 +15,9 @@
<p><a href="06_interpolation.html">06_interpolation.html</a></p> <p><a href="06_interpolation.html">06_interpolation.html</a></p>
<p><a href="07_scrollingAndSorting.html">07_scrollingAndSorting.html</a></p> <p><a href="07_scrollingAndSorting.html">07_scrollingAndSorting.html</a></p>
<p><a href="08_performance.html">08_performance.html</a></p> <p><a href="08_performance.html">08_performance.html</a></p>
<p><a href="09_external_legend.html">09_external_legend.html</a></p>
<p><a href="10_barsSideBySide.html">10_barsSideBySide.html</a></p>
<p><a href="11_barsSideBySideGroups.html">11_barsSideBySideGroups.html</a></p>
</div> </div>
</body> </body>

+ 2
- 2
lib/network/Node.js View File

@ -159,7 +159,7 @@ Node.prototype.setProperties = function(properties, constants) {
} }
// copy group properties // copy group properties
if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) {
if (typeof this.options.group === 'number' || (typeof this.options.group === 'string' && this.options.group != '')) {
var groupObj = this.grouplist.get(this.options.group); var groupObj = this.grouplist.get(this.options.group);
for (var prop in groupObj) { for (var prop in groupObj) {
if (groupObj.hasOwnProperty(prop)) { if (groupObj.hasOwnProperty(prop)) {
@ -640,7 +640,7 @@ Node.prototype._resizeCircle = function (ctx) {
var margin = 5; var margin = 5;
var textSize = this.getTextSize(ctx); var textSize = this.getTextSize(ctx);
var diameter = Math.max(textSize.width, textSize.height) + 2 * margin; var diameter = Math.max(textSize.width, textSize.height) + 2 * margin;
this.options.radius= diameter / 2;
this.options.radius = diameter / 2;
this.width = diameter; this.width = diameter;
this.height = diameter; this.height = diameter;

+ 2
- 2
lib/timeline/component/GraphGroup.js View File

@ -9,7 +9,7 @@ var DOMutil = require('../../DOMutil');
*/ */
function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) { function GraphGroup (group, groupId, options, groupsUsingDefaultStyles) {
this.id = groupId; this.id = groupId;
var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom']
var fields = ['sampling','style','sort','yAxisOrientation','barChart','drawPoints','shaded','catmullRom','slots']
this.options = util.selectiveBridgeObject(fields,options); this.options = util.selectiveBridgeObject(fields,options);
this.usingDefaultStyle = group.className === undefined; this.usingDefaultStyle = group.className === undefined;
this.groupsUsingDefaultStyles = groupsUsingDefaultStyles; this.groupsUsingDefaultStyles = groupsUsingDefaultStyles;
@ -40,7 +40,7 @@ GraphGroup.prototype.setZeroPosition = function(pos) {
GraphGroup.prototype.setOptions = function(options) { GraphGroup.prototype.setOptions = function(options) {
if (options !== undefined) { if (options !== undefined) {
var fields = ['sampling','style','sort','yAxisOrientation','barChart'];
var fields = ['sampling','style','sort','yAxisOrientation','barChart','slots'];
util.selectiveDeepExtend(fields, this.options, options); util.selectiveDeepExtend(fields, this.options, options);
util.mergeOptions(this.options, options,'catmullRom'); util.mergeOptions(this.options, options,'catmullRom');

+ 64
- 6
lib/timeline/component/LineGraph.js View File

@ -33,6 +33,7 @@ function LineGraph(body, options) {
style: 'line', // line, bar style: 'line', // line, bar
barChart: { barChart: {
width: 50, width: 50,
allowOverlap: true,
align: 'center' // left, center, right align: 'center' // left, center, right
}, },
catmullRom: { catmullRom: {
@ -762,18 +763,46 @@ LineGraph.prototype._drawBarGraph = function (dataset, group) {
var coreDistance; var coreDistance;
var minWidth = 0.1 * group.options.barChart.width; var minWidth = 0.1 * group.options.barChart.width;
var offset = 0; var offset = 0;
var width = group.options.barChart.width;
if (group.options.barChart.align == 'left') {offset -= 0.5*width;}
else if (group.options.barChart.align == 'right') {offset += 0.5*width;}
// check for intersections
var intersections = {};
for (var i = 0; i < dataset.length; i++) { for (var i = 0; i < dataset.length; i++) {
// dynammically downscale the width so there is no overlap up to 1/10th the original width
if (i+1 < dataset.length) {coreDistance = Math.abs(dataset[i+1].x - dataset[i].x);} if (i+1 < dataset.length) {coreDistance = Math.abs(dataset[i+1].x - dataset[i].x);}
if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(dataset[i-1].x - dataset[i].x));} if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(dataset[i-1].x - dataset[i].x));}
if (coreDistance < width) {width = coreDistance < minWidth ? minWidth : coreDistance;}
if (coreDistance == 0) {
if (intersections[dataset[i].x] === undefined) {
intersections[dataset[i].x] = {amount:0, resolved:0};
}
intersections[dataset[i].x].amount += 1;
}
}
DOMutil.drawBar(dataset[i].x + offset, dataset[i].y, width, group.zeroPosition - dataset[i].y, group.className + ' bar', this.svgElements, this.svg);
// plot the bargraph
var key;
for (var i = 0; i < dataset.length; i++) {
key = dataset[i].x;
if (intersections[key] === undefined) {
if (i+1 < dataset.length) {coreDistance = Math.abs(dataset[i+1].x - key);}
if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(dataset[i-1].x - key));}
var drawData = this._getSafeDrawData(coreDistance, group, minWidth);
}
else {
var nextKey = i + (intersections[key].amount - intersections[key].resolved);
var prevKey = i - (intersections[key].resolved + 1);
if (nextKey < dataset.length) {coreDistance = Math.abs(dataset[nextKey].x - key);}
if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(dataset[prevKey].x - key));}
var drawData = this._getSafeDrawData(coreDistance, group, minWidth);
intersections[key].resolved += 1;
if (group.options.barChart.allowOverlap == false) {
drawData.width = drawData.width / intersections[key].amount;
drawData.offset += (intersections[key].resolved) * drawData.width - (0.5*drawData.width * (intersections[key].amount+1));
if (group.options.barChart.align == 'left') {offset -= 0.5*drawData.width;}
else if (group.options.barChart.align == 'right') {offset += 0.5*drawData.width;}
}
}
DOMutil.drawBar(dataset[i].x + drawData.offset, dataset[i].y, drawData.width, group.zeroPosition - dataset[i].y, group.className + ' bar', this.svgElements, this.svg);
} }
// draw points // draw points
@ -784,6 +813,35 @@ LineGraph.prototype._drawBarGraph = function (dataset, group) {
} }
}; };
LineGraph.prototype._getSafeDrawData = function (coreDistance, group, minWidth) {
var width, offset;
if (coreDistance < group.options.barChart.width && coreDistance > 0) {
width = coreDistance < minWidth ? minWidth : coreDistance;
offset = 0; // recalculate offset with the new width;
if (group.options.slots) { // recalculate the shared width and offset if these options are set.
width = (width / group.options.slots.total);
offset = group.options.slots.slot * width - (0.5*width * (group.options.slots.total+1));
}
if (group.options.barChart.align == 'left') {offset -= 0.5*coreDistance;}
else if (group.options.barChart.align == 'right') {offset += 0.5*coreDistance;}
}
else {
// no collisions, plot with default settings
width = group.options.barChart.width;
offset = 0;
if (group.options.slots) {
// if the groups are sharing the same points, this allows them to be plotted side by side
width = width / group.options.slots.total;
offset = group.options.slots.slot * width - (0.5*width * (group.options.slots.total+1));
}
if (group.options.barChart.align == 'left') {offset -= 0.5*group.options.barChart.width;}
else if (group.options.barChart.align == 'right') {offset += 0.5*group.options.barChart.width;}
}
return {width: width, offset: offset};
}
/** /**
* draw a line graph * draw a line graph

Loading…
Cancel
Save