Browse Source

Merge remote-tracking branch 'origin/develop' into develop

codeClimate
jos 9 years ago
parent
commit
00e791af7b
9 changed files with 151 additions and 49 deletions
  1. +10
    -3
      HISTORY.md
  2. +43
    -0
      lib/DataView.js
  3. +1
    -1
      lib/timeline/component/DataAxis.js
  4. +5
    -15
      lib/timeline/component/GraphGroup.js
  5. +32
    -13
      lib/timeline/component/LineGraph.js
  6. +40
    -15
      lib/timeline/component/graph2d_types/bar.js
  7. +0
    -1
      lib/timeline/component/graph2d_types/points.js
  8. +3
    -1
      lib/timeline/optionsGraph2d.js
  9. +17
    -0
      lib/util.js

+ 10
- 3
HISTORY.md View File

@ -18,13 +18,20 @@ http://visjs.org
### Graph2d
- Implemented a new option for `shaded.orientation` to always shade towards zero.
Thanks @ludost.
- Fixed support for using a `DataView` in Graph2d. Thanks @ludost.
- Large refactoring of Graph2d code base:
- Implemented a new option for `shaded.orientation` to always shade towards zero.
- Implemented a new option for `shaded.orientation` to follow another group (fill in between)
- Implemented line-graph stacking
- Fixed support for using a `DataView` in Graph2d.
- Implemented a new zindex option for controlling svg rendering order.
- Performance updates and fixes
### DataSet
- Fixed #1487: DataSet cannot remove an item with id `0` correctly.
### DataView
- Added the map() function from DataSet.
## 2015-11-27, version 4.10.0

+ 43
- 0
lib/DataView.js View File

@ -230,6 +230,49 @@ DataView.prototype.getIds = function (options) {
return ids;
};
/**
* Map every item in the dataset.
* @param {function} callback
* @param {Object} [options] Available options:
* {Object.<String, String>} [type]
* {String[]} [fields] filter fields
* {function} [filter] filter items
* {String | function} [order] Order the items by
* a field name or custom sort function.
* @return {Object[]} mappedItems
*/
DataView.prototype.map = function (callback,options) {
var mappedItems = [];
if (this._data) {
var defaultFilter = this._options.filter;
var filter;
if (options && options.filter) {
if (defaultFilter) {
filter = function (item) {
return defaultFilter(item) && options.filter(item);
}
}
else {
filter = options.filter;
}
}
else {
filter = defaultFilter;
}
mappedItems = this._data.map(callback,{
filter: filter,
order: options && options.order
});
}
else {
mappedItems = [];
}
return mappedItems;
};
/**
* Get the DataSet to which this DataView is connected. In case there is a chain
* of multiple DataViews, the root DataSet of this chain is returned.

+ 1
- 1
lib/timeline/component/DataAxis.js View File

@ -59,7 +59,7 @@ function DataAxis (body, options, svg, linegraphOptions) {
this.setOptions(options);
this.width = Number(('' + this.options.width).replace("px",""));
this.minWidth = this.width;
this.height = this.linegraphSVG.offsetHeight;
this.height = this.linegraphSVG.getBoundingClientRect().height;
this.hidden = false;
this.stepPixels = 25;

+ 5
- 15
lib/timeline/component/GraphGroup.js View File

@ -16,7 +16,7 @@ var Points = require('./graph2d_types/points');
*/
function GraphGroup(group, groupId, options, groupsUsingDefaultStyles) {
this.id = groupId;
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation'];
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation', 'zIndex'];
this.options = util.selectiveBridgeObject(fields, options);
this.usingDefaultStyle = group.className === undefined;
this.groupsUsingDefaultStyles = groupsUsingDefaultStyles;
@ -29,17 +29,6 @@ function GraphGroup(group, groupId, options, groupsUsingDefaultStyles) {
this.visible = group.visible === undefined ? true : group.visible;
}
function insertionSort (a,compare) {
for (var i = 0; i < a.length; i++) {
var k = a[i];
for (var j = i; j > 0 && compare(k,a[j - 1])<0; j--) {
a[j] = a[j - 1];
}
a[j] = k;
}
return a;
}
/**
* this loads a reference to all items in this group into this group.
* @param {array} items
@ -48,7 +37,7 @@ GraphGroup.prototype.setItems = function (items) {
if (items != null) {
this.itemsData = items;
if (this.options.sort == true) {
insertionSort(this.itemsData,function (a, b) {
util.insertSort(this.itemsData,function (a, b) {
return a.x > b.x ? 1 : -1;
});
}
@ -76,7 +65,7 @@ GraphGroup.prototype.setZeroPosition = function (pos) {
*/
GraphGroup.prototype.setOptions = function (options) {
if (options !== undefined) {
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'excludeFromLegend', 'excludeFromStacking'];
var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'excludeFromLegend', 'excludeFromStacking', 'zIndex'];
util.selectiveDeepExtend(fields, this.options, options);
// if the group's drawPoints is a function delegate the callback to the onRender property
@ -145,7 +134,8 @@ GraphGroup.prototype.getLegend = function (iconWidth, iconHeight, framework, x,
case "line":
Lines.drawIcon(this, x, y, iconWidth, iconHeight, framework);
break;
case "points":
case "points": //explicit no break
case "point":
Points.drawIcon(this, x, y, iconWidth, iconHeight, framework);
break;
case "bar":

+ 32
- 13
lib/timeline/component/LineGraph.js View File

@ -312,7 +312,6 @@ LineGraph.prototype.setItems = function (items) {
ids = this.itemsData.getIds();
this._onAdd(ids);
}
this.redraw(true);
};
@ -333,7 +332,9 @@ LineGraph.prototype.setGroups = function (groups) {
// remove all drawn groups
ids = this.groupsData.getIds();
this.groupsData = null;
this._onRemoveGroups(ids); // note: this will cause a redraw
for (var i = 0; i < ids.length; i++) {
this._removeGroup(ids[i]);
}
}
// replace the dataset
@ -358,7 +359,6 @@ LineGraph.prototype.setGroups = function (groups) {
ids = this.groupsData.getIds();
this._onAddGroups(ids);
}
this._onUpdate();
};
LineGraph.prototype._onUpdate = function (ids) {
@ -593,6 +593,31 @@ LineGraph.prototype.redraw = function (forceGraphUpdate) {
};
LineGraph.prototype._getSortedGroupIds = function(){
// getting group Ids
var grouplist = [];
for (var groupId in this.groups) {
if (this.groups.hasOwnProperty(groupId)) {
var group = this.groups[groupId];
if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) {
grouplist.push({id:groupId,zIndex:group.options.zIndex});
}
}
}
util.insertSort(grouplist,function(a,b){
var az = a.zIndex;
var bz = b.zIndex;
if (az === undefined) az=0;
if (bz === undefined) bz=0;
return az==bz? 0: (az<bz ? -1: 1);
});
var groupIds = new Array(grouplist.length);
for (var i=0; i< grouplist.length; i++){
groupIds[i] = grouplist[i].id;
}
return groupIds;
}
/**
* Update and redraw the graph.
*
@ -609,15 +634,7 @@ LineGraph.prototype._updateGraph = function () {
var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width);
// getting group Ids
var groupIds = [];
for (var groupId in this.groups) {
if (this.groups.hasOwnProperty(groupId)) {
group = this.groups[groupId];
if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) {
groupIds.push(groupId);
}
}
}
var groupIds = this._getSortedGroupIds();
if (groupIds.length > 0) {
var groupsData = {};
@ -715,8 +732,10 @@ LineGraph.prototype._updateGraph = function () {
}
Lines.draw(paths[groupIds[i]], group, this.framework);
//explicit no break;
case "point":
//explicit no break;
case "points":
if (group.options.style == "points" || group.options.drawPoints.enabled == true) {
if (group.options.style == "point" || group.options.style == "points" || group.options.drawPoints.enabled == true) {
Points.draw(groupsData[groupIds[i]], group, this.framework);
}
break;

+ 40
- 15
lib/timeline/component/graph2d_types/bar.js View File

@ -16,6 +16,8 @@ Bargraph.drawIcon = function (group, x, y, iconWidth, iconHeight, framework) {
outline.setAttributeNS(null, "class", "vis-outline");
var barWidth = Math.round(0.3 * iconWidth);
var originalWidth = group.options.barChart.width;
var scale = originalWidth / barWidth;
var bar1Height = Math.round(0.4 * iconHeight);
var bar2Height = Math.round(0.75 * iconHeight);
@ -28,7 +30,7 @@ Bargraph.drawIcon = function (group, x, y, iconWidth, iconHeight, framework) {
var groupTemplate = {
style: group.options.drawPoints.style,
styles: group.options.drawPoints.styles,
size: Math.max(barWidth/5,group.options.drawPoints.size),
size: (group.options.drawPoints.size / scale),
className: group.className
};
DOMutil.drawPoint(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, groupTemplate, framework.svgElements, framework.svg);
@ -49,7 +51,7 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
var coreDistance;
var key, drawData;
var group;
var i,j;
var i, j;
var barPoints = 0;
// combine all barchart data
@ -61,6 +63,8 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
combinedData.push({
screen_x: processedGroupData[groupIds[i]][j].screen_x,
screen_y: processedGroupData[groupIds[i]][j].screen_y,
x: processedGroupData[groupIds[i]][j].x,
y: processedGroupData[groupIds[i]][j].y,
groupId: groupIds[i],
label: processedGroupData[groupIds[i]][j].label
});
@ -70,7 +74,9 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
}
}
if (barPoints === 0) {return;}
if (barPoints === 0) {
return;
}
// sort by time and by group
combinedData.sort(function (a, b) {
@ -93,15 +99,23 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
key = combinedData[i].screen_x;
var heightOffset = 0;
if (intersections[key] === undefined) {
if (i+1 < combinedData.length) {coreDistance = Math.abs(combinedData[i+1].screen_x - key);}
if (i > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[i-1].screen_x - key));}
if (i + 1 < combinedData.length) {
coreDistance = Math.abs(combinedData[i + 1].screen_x - key);
}
if (i > 0) {
coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].screen_x - key));
}
drawData = Bargraph._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].screen_x - key);}
if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].screen_x - key));}
if (nextKey < combinedData.length) {
coreDistance = Math.abs(combinedData[nextKey].screen_x - key);
}
if (prevKey > 0) {
coreDistance = Math.min(coreDistance, Math.abs(combinedData[prevKey].screen_x - key));
}
drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
intersections[key].resolved += 1;
@ -117,17 +131,23 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
}
else if (group.options.barChart.sideBySide === true) {
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') {drawData.offset -= 0.5*drawData.width;}
else if (group.options.barChart.align === 'right') {drawData.offset += 0.5*drawData.width;}
drawData.offset += (intersections[key].resolved) * drawData.width - (0.5 * drawData.width * (intersections[key].amount + 1));
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].screen_x + drawData.offset, combinedData[i].screen_y - heightOffset, drawData.width, group.zeroPosition - combinedData[i].screen_y, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
// draw points
if (group.options.drawPoints.enabled === true) {
let pointData = {
screen_x:combinedData[i].screen_x,
screen_y:combinedData[i].screen_y - heightOffset,
screen_x: combinedData[i].screen_x,
screen_y: combinedData[i].screen_y - heightOffset,
x: combinedData[i].x,
y: combinedData[i].y,
groupId: combinedData[i].groupId,
label: combinedData[i].label
};
@ -156,7 +176,12 @@ Bargraph._getDataIntersections = function (intersections, combinedData) {
}
if (coreDistance === 0) {
if (intersections[combinedData[i].screen_x] === undefined) {
intersections[combinedData[i].screen_x] = {amount: 0, resolved: 0, accumulatedPositive: 0, accumulatedNegative: 0};
intersections[combinedData[i].screen_x] = {
amount: 0,
resolved: 0,
accumulatedPositive: 0,
accumulatedNegative: 0
};
}
intersections[combinedData[i].screen_x].amount += 1;
}
@ -201,13 +226,13 @@ Bargraph._getSafeDrawData = function (coreDistance, group, minWidth) {
return {width: width, offset: offset};
};
Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupLabel, orientation) {
Bargraph.getStackedYRange = function (combinedData, groupRanges, groupIds, groupLabel, orientation) {
if (combinedData.length > 0) {
// sort by time and by group
combinedData.sort(function (a, b) {
if (a.screen_x === b.screen_x) {
return a.groupId < b.groupId ? -1 : 1;
}
}
else {
return a.screen_x - b.screen_x;
}

+ 0
- 1
lib/timeline/component/graph2d_types/points.js View File

@ -66,7 +66,6 @@ function getCallback(framework, group) {
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;
}

+ 3
- 1
lib/timeline/optionsGraph2d.js View File

@ -162,6 +162,7 @@ let allOptions = {
zoomKey: {string: ['ctrlKey', 'altKey', 'metaKey', '']},
zoomMax: {number},
zoomMin: {number},
zIndex: {number},
__type__: {object}
};
@ -265,7 +266,8 @@ let configureOptions = {
zoomable: true,
zoomKey: ['ctrlKey', 'altKey', 'metaKey', ''],
zoomMax: [315360000000000, 10, 315360000000000, 1],
zoomMin: [10, 10, 315360000000000, 1]
zoomMin: [10, 10, 315360000000000, 1],
zIndex: 0
}
};

+ 17
- 0
lib/util.js View File

@ -1253,6 +1253,23 @@ exports.bridgeObject = function (referenceObject) {
}
};
/**
* This method provides a stable sort implementation, very fast for presorted data
*
* @param a the array
* @param a order comparator
* @returns {the array}
*/
exports.insertSort = function (a,compare) {
for (var i = 0; i < a.length; i++) {
var k = a[i];
for (var j = i; j > 0 && compare(k,a[j - 1])<0; j--) {
a[j] = a[j - 1];
}
a[j] = k;
}
return a;
}
/**
* this is used to set the options of subobjects in the options object. A requirement of these subobjects

Loading…
Cancel
Save