Browse Source

Fixed bug where empty groups would crash graph2d, cleaned code

v3_develop
Alex de Mulder 10 years ago
parent
commit
c5f4b2afcd
2 changed files with 24518 additions and 24500 deletions
  1. +24410
    -24401
      dist/vis.js
  2. +108
    -99
      lib/timeline/component/LineGraph.js

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


+ 108
- 99
lib/timeline/component/LineGraph.js View File

@ -339,7 +339,11 @@ LineGraph.prototype.setGroups = function(groups) {
};
/**
* Update the datapoints
* @param [ids]
* @private
*/
LineGraph.prototype._onUpdate = function(ids) {
this._updateUngrouped();
this._updateAllGroupData();
@ -417,7 +421,8 @@ LineGraph.prototype._updateGroup = function (group, groupId) {
LineGraph.prototype._updateAllGroupData = function () {
if (this.itemsData != null) {
var groupsContent = {};
for (var groupId in this.groups) {
var groupId;
for (groupId in this.groups) {
if (this.groups.hasOwnProperty(groupId)) {
groupsContent[groupId] = [];
}
@ -429,7 +434,7 @@ LineGraph.prototype._updateAllGroupData = function () {
groupsContent[item.group].push(item);
}
}
for (var groupId in this.groups) {
for (groupId in this.groups) {
if (this.groups.hasOwnProperty(groupId)) {
this.groups[groupId].setItems(groupsContent[groupId]);
}
@ -467,20 +472,6 @@ LineGraph.prototype._updateUngrouped = function() {
}
}
// much much slower
// var datapoints = this.itemsData.get({
// filter: function (item) {return item.group === undefined;},
// showInternalIds:true
// });
// if (datapoints.length > 0) {
// var updateQuery = [];
// for (var i = 0; i < datapoints.length; i++) {
// updateQuery.push({id:datapoints[i].id, group: UNGROUPED});
// }
// this.itemsData.update(updateQuery, true);
// }
// var t1 = new Date();
// var pointInUNGROUPED = this.itemsData.get({filter: function (item) {return item.group == UNGROUPED;}});
if (ungroupedCounter == 0) {
delete this.groups[UNGROUPED];
this.legendLeft.removeGroup(UNGROUPED);
@ -488,8 +479,6 @@ LineGraph.prototype._updateUngrouped = function() {
this.yAxisLeft.removeGroup(UNGROUPED);
this.yAxisRight.removeGroup(UNGROUPED);
}
// console.log("getting amount ungrouped",new Date() - t1);
// console.log("putting in ungrouped",new Date() - t0);
}
else {
delete this.groups[UNGROUPED];
@ -618,17 +607,17 @@ LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate,
// what data we need to draw. Sorted data is much faster.
// more optimization is possible by doing the sampling before and using the binary search
// to find the end date to determine the increment.
var group;
var group, i, j, item;
if (groupIds.length > 0) {
for (var i = 0; i < groupIds.length; i++) {
for (i = 0; i < groupIds.length; i++) {
group = this.groups[groupIds[i]];
groupsData[groupIds[i]] = [];
var dataContainer = groupsData[groupIds[i]];
// optimization for sorted data
if (group.options.sort == true) {
var guess = Math.max(0, util.binarySearchGeneric(group.itemsData, minDate, 'x', 'before'));
for (var j = guess; j < group.itemsData.length; j++) {
var item = group.itemsData[j];
for (j = guess; j < group.itemsData.length; j++) {
item = group.itemsData[j];
if (item !== undefined) {
if (item.x > maxDate) {
dataContainer.push(item);
@ -641,8 +630,8 @@ LineGraph.prototype._getRelevantData = function (groupIds, groupsData, minDate,
}
}
else {
for (var j = 0; j < group.itemsData.length; j++) {
var item = group.itemsData[j];
for (j = 0; j < group.itemsData.length; j++) {
item = group.itemsData[j];
if (item !== undefined) {
if (item.x > minDate && item.x < maxDate) {
dataContainer.push(item);
@ -663,64 +652,70 @@ LineGraph.prototype._applySampling = function (groupIds, groupsData) {
group = this.groups[groupIds[i]];
if (group.options.sampling == true) {
var dataContainer = groupsData[groupIds[i]];
var increment = 1;
var amountOfPoints = dataContainer.length;
if (dataContainer.length > 0) {
var increment = 1;
var amountOfPoints = dataContainer.length;
// the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop
// of width changing of the yAxis.
var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x);
var pointsPerPixel = amountOfPoints / xDistance;
increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel)));
// the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop
// of width changing of the yAxis.
var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x);
var pointsPerPixel = amountOfPoints / xDistance;
increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel)));
var sampledData = [];
for (var j = 0; j < amountOfPoints; j += increment) {
sampledData.push(dataContainer[j]);
var sampledData = [];
for (var j = 0; j < amountOfPoints; j += increment) {
sampledData.push(dataContainer[j]);
}
groupsData[groupIds[i]] = sampledData;
}
groupsData[groupIds[i]] = sampledData;
}
}
}
};
LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) {
var groupData, group;
var groupData, group, i,j;
var barCombinedDataLeft = [];
var barCombinedDataRight = [];
var barCombinedData;
if (groupIds.length > 0) {
for (var i = 0; i < groupIds.length; i++) {
for (i = 0; i < groupIds.length; i++) {
groupData = groupsData[groupIds[i]];
group = this.groups[groupIds[i]];
if (group.options.style == 'line' || group.options.barChart.handleOverlap != "stack") {
var yMin = groupData[0].y;
var yMax = groupData[0].y;
for (var j = 0; j < groupData.length; j++) {
yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
}
groupRanges[groupIds[i]] = {min: yMin, max: yMax, yAxisOrientation: group.options.yAxisOrientation};
}
else if (group.options.style == 'bar') {
if (group.options.yAxisOrientation == 'left') {
barCombinedData = barCombinedDataLeft;
}
else {
barCombinedData = barCombinedDataRight;
if (groupData.length > 0) {
group = this.groups[groupIds[i]];
if (group.options.style == 'line' || group.options.barChart.handleOverlap != "stack") {
var yMin = groupData[0].y;
var yMax = groupData[0].y;
for (j = 0; j < groupData.length; j++) {
yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
}
groupRanges[groupIds[i]] = {min: yMin, max: yMax, yAxisOrientation: group.options.yAxisOrientation};
}
else if (group.options.style == 'bar') {
if (group.options.yAxisOrientation == 'left') {
barCombinedData = barCombinedDataLeft;
}
else {
barCombinedData = barCombinedDataRight;
}
groupRanges[groupIds[i]] = {min: 0, max: 0, yAxisOrientation: group.options.yAxisOrientation, ignore: true};
groupRanges[groupIds[i]] = {min: 0, max: 0, yAxisOrientation: group.options.yAxisOrientation, ignore: true};
// combine data
for (var j = 0; j < groupData.length; j++) {
barCombinedData.push({
x: groupData[j].x,
y: groupData[j].y,
groupId: groupIds[i]
});
// combine data
for (j = 0; j < groupData.length; j++) {
barCombinedData.push({
x: groupData[j].x,
y: groupData[j].y,
groupId: groupIds[i]
});
}
}
}
}
var intersections;
if (barCombinedDataLeft.length > 0) {
// sort by time and by group
barCombinedDataLeft.sort(function (a, b) {
@ -729,8 +724,8 @@ LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) {
} else {
return a.x - b.x;
}
})
var intersections = {};
});
intersections = {};
this._getDataIntersections(intersections, barCombinedDataLeft);
groupRanges["__barchartLeft"] = this._getStackedBarYRange(intersections, barCombinedDataLeft);
groupRanges["__barchartLeft"].yAxisOrientation = "left";
@ -744,8 +739,8 @@ LineGraph.prototype._getYRanges = function (groupIds, groupsData, groupRanges) {
} else {
return a.x - b.x;
}
})
var intersections = {};
});
intersections = {};
this._getDataIntersections(intersections, barCombinedDataRight);
groupRanges["__barchartRight"] = this._getStackedBarYRange(intersections, barCombinedDataRight);
groupRanges["__barchartRight"].yAxisOrientation = "right";
@ -781,7 +776,8 @@ LineGraph.prototype._getStackedBarYRange = function (intersections, combinedData
/**
* this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden.
* @param {array} groupIds
* @param {Array} groupIds
* @param {Object} groupRanges
* @private
*/
LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
@ -789,23 +785,24 @@ LineGraph.prototype._updateYAxis = function (groupIds, groupRanges) {
var yAxisLeftUsed = false;
var yAxisRightUsed = false;
var minLeft = 1e9, minRight = 1e9, maxLeft = -1e9, maxRight = -1e9, minVal, maxVal;
// if groups are present
if (groupIds.length > 0) {
for (var i = 0; i < groupIds.length; i++) {
if (groupRanges[groupIds[i]].ignore !== true) {
minVal = groupRanges[groupIds[i]].min;
maxVal = groupRanges[groupIds[i]].max;
if (groupRanges[groupIds[i]].yAxisOrientation == 'left') {
yAxisLeftUsed = true;
minLeft = minLeft > minVal ? minVal : minLeft;
maxLeft = maxLeft < maxVal ? maxVal : maxLeft;
}
else {
yAxisRightUsed = true;
minRight = minRight > minVal ? minVal : minRight;
maxRight = maxRight < maxVal ? maxVal : maxRight;
if (groupRanges.hasOwnProperty(groupIds[i])) {
if (groupRanges[groupIds[i]].ignore !== true) {
minVal = groupRanges[groupIds[i]].min;
maxVal = groupRanges[groupIds[i]].max;
if (groupRanges[groupIds[i]].yAxisOrientation == 'left') {
yAxisLeftUsed = true;
minLeft = minLeft > minVal ? minVal : minLeft;
maxLeft = maxLeft < maxVal ? maxVal : maxLeft;
}
else {
yAxisRightUsed = true;
minRight = minRight > minVal ? minVal : minRight;
maxRight = maxRight < maxVal ? maxVal : maxRight;
}
}
}
}
@ -883,14 +880,15 @@ LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) {
/**
* draw a bar graph
* @param datapoints
* @param group
*
* @param groupIds
* @param processedGroupData
*/
LineGraph.prototype._drawBarGraphs = function (groupIds, processedGroupData) {
var combinedData = [];
var intersections = {};
var coreDistance;
var key;
var key, drawData;
var group;
var i,j;
var barPoints = 0;
@ -936,14 +934,14 @@ LineGraph.prototype._drawBarGraphs = function (groupIds, processedGroupData) {
if (intersections[key] === undefined) {
if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].x - key);}
if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].x - key));}
var drawData = this._getSafeDrawData(coreDistance, group, minWidth);
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 < combinedData.length) {coreDistance = Math.abs(combinedData[nextKey].x - key);}
if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].x - key));}
var drawData = this._getSafeDrawData(coreDistance, group, minWidth);
drawData = this._getSafeDrawData(coreDistance, group, minWidth);
intersections[key].resolved += 1;
if (group.options.barChart.handleOverlap == 'stack') {
@ -953,8 +951,8 @@ LineGraph.prototype._drawBarGraphs = function (groupIds, processedGroupData) {
else if (group.options.barChart.handleOverlap == 'sideBySide') {
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;}
if (group.options.barChart.align == 'left') {drawData.offset -= 0.5*drawData.width;}
else if (group.options.barChart.align == 'right') {drawData.offset += 0.5*drawData.width;}
}
}
DOMutil.drawBar(combinedData[i].x + drawData.offset, combinedData[i].y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].y, group.className + ' bar', this.svgElements, this.svg);
@ -965,7 +963,12 @@ LineGraph.prototype._drawBarGraphs = function (groupIds, processedGroupData) {
}
};
/**
* Fill the intersections object with counters of how many datapoints share the same x coordinates
* @param intersections
* @param combinedData
* @private
*/
LineGraph.prototype._getDataIntersections = function (intersections, combinedData) {
// get intersections
var coreDistance;
@ -985,10 +988,15 @@ LineGraph.prototype._getDataIntersections = function (intersections, combinedDat
}
};
//LineGraph.prototype._accumulate = function (intersections, combinedData) {
/**
* Get the width and offset for bargraphs based on the coredistance between datapoints
*
* @param coreDistance
* @param group
* @param minWidth
* @returns {{width: Number, offset: Number}}
* @private
*/
LineGraph.prototype._getSafeDrawData = function (coreDistance, group, minWidth) {
var width, offset;
if (coreDistance < group.options.barChart.width && coreDistance > 0) {
@ -1003,7 +1011,7 @@ LineGraph.prototype._getSafeDrawData = function (coreDistance, group, minWidth)
}
}
else {
// no collisions, plot with default settings
// default settings
width = group.options.barChart.width;
offset = 0;
if (group.options.barChart.align == 'left') {
@ -1021,7 +1029,7 @@ LineGraph.prototype._getSafeDrawData = function (coreDistance, group, minWidth)
/**
* draw a line graph
*
* @param datapoints
* @param dataset
* @param group
*/
LineGraph.prototype._drawLineGraph = function (dataset, group) {
@ -1067,10 +1075,11 @@ LineGraph.prototype._drawLineGraph = function (dataset, group) {
/**
* draw the data points
*
* @param dataset
* @param JSONcontainer
* @param svg
* @param group
* @param {Array} dataset
* @param {Object} JSONcontainer
* @param {Object} svg | SVG DOM element
* @param {GraphGroup} group
* @param {Number} [offset]
*/
LineGraph.prototype._drawPoints = function (dataset, group, JSONcontainer, svg, offset) {
if (offset === undefined) {offset = 0;}

Loading…
Cancel
Save