Browse Source

Don't copy datapoints on every render, only add render data to existing copy.

newShading
Ludo Stellingwerff 9 years ago
parent
commit
f53a8b73ab
4 changed files with 68 additions and 81 deletions
  1. +11
    -30
      lib/timeline/component/LineGraph.js
  2. +29
    -29
      lib/timeline/component/graph2d_types/bar.js
  3. +26
    -20
      lib/timeline/component/graph2d_types/line.js
  4. +2
    -2
      lib/timeline/component/graph2d_types/points.js

+ 11
- 30
lib/timeline/component/LineGraph.js View File

@ -591,8 +591,6 @@ LineGraph.prototype._updateGraph = function () {
DOMutil.prepareElements(this.svgElements);
if (this.props.width != 0 && this.itemsData != null) {
var group, i;
var preprocessedGroupData = {};
var processedGroupData = {};
var groupRanges = {};
var changeCalled = false;
// this is the range of the SVG canvas
@ -620,11 +618,11 @@ LineGraph.prototype._updateGraph = function () {
// we transform the X coordinates to detect collisions
for (i = 0; i < groupIds.length; i++) {
preprocessedGroupData[groupIds[i]] = this._convertXcoordinates(groupsData[groupIds[i]]);
this._convertXcoordinates(groupsData[groupIds[i]]);
}
// now all needed data has been collected we start the processing.
this._getYRanges(groupIds, preprocessedGroupData, groupRanges);
this._getYRanges(groupIds, groupsData, groupRanges);
// update the Y axis first, we use this data to draw at the correct Y points
// changeCalled is required to clean the SVG on a change emit.
@ -650,7 +648,7 @@ LineGraph.prototype._updateGraph = function () {
if (this.options.stack === true && this.options.style === 'line' && i > 0) {
this._stack(groupsData[groupIds[i]], groupsData[groupIds[i - 1]]);
}
processedGroupData[groupIds[i]] = this._convertYcoordinates(groupsData[groupIds[i]], group);
this._convertYcoordinates(groupsData[groupIds[i]], group);
}
//Precalculate paths and draw shading if appropriate. This will make sure the shading is always behind any lines.
@ -658,7 +656,7 @@ LineGraph.prototype._updateGraph = function () {
for (i = 0; i < groupIds.length; i++) {
group = this.groups[groupIds[i]];
if (group.options.style === 'line' && group.options.shaded.enabled == true) {
var dataset = processedGroupData[groupIds[i]];
var dataset = groupsData[groupIds[i]];
if (!paths.hasOwnProperty(groupIds[i])) {
paths[groupIds[i]] = Lines.calcPath(dataset, group);
}
@ -669,7 +667,7 @@ LineGraph.prototype._updateGraph = function () {
continue;
}
if (!paths.hasOwnProperty(subGroupId)) {
paths[subGroupId] = Lines.calcPath(processedGroupData[subGroupId], this.groups[subGroupId]);
paths[subGroupId] = Lines.calcPath(groupsData[subGroupId], this.groups[subGroupId]);
}
Lines.drawShading(paths[groupIds[i]], group, paths[subGroupId], this.framework);
}
@ -680,20 +678,20 @@ LineGraph.prototype._updateGraph = function () {
}
// draw the groups, calculating paths if still necessary.
Bars.draw(groupIds, processedGroupData, this.framework);
Bars.draw(groupIds, groupsData, this.framework);
for (i = 0; i < groupIds.length; i++) {
group = this.groups[groupIds[i]];
if (processedGroupData[groupIds[i]].length > 0) {
if (groupsData[groupIds[i]].length > 0) {
switch (group.options.style) {
case "line":
if (!paths.hasOwnProperty(groupIds[i])) {
paths[groupIds[i]] = Lines.calcPath(processedGroupData[groupIds[i]], group);
paths[groupIds[i]] = Lines.calcPath(groupsData[groupIds[i]], group);
}
Lines.draw(paths[groupIds[i]], group, this.framework);
//explicit no break;
case "points":
if (group.options.style == "points" || group.options.drawPoints.enabled == true) {
Points.draw(processedGroupData[groupIds[i]], group, this.framework);
Points.draw(groupsData[groupIds[i]], group, this.framework);
}
break;
case "bar":
@ -1013,17 +1011,10 @@ LineGraph.prototype._toggleAxisVisiblity = function (axisUsed, axis) {
* @private
*/
LineGraph.prototype._convertXcoordinates = function (datapoints) {
var extractedData = new Array(datapoints.length);
var xValue, yValue;
var toScreen = this.body.util.toScreen;
for (var i = 0; i < datapoints.length; i++) {
xValue = toScreen(datapoints[i].x) + this.props.width;
yValue = datapoints[i].y;
extractedData[i] = {x: xValue, y: yValue};
datapoints[i].screen_x = toScreen(datapoints[i].x) + this.props.width;
}
return extractedData;
};
@ -1038,25 +1029,15 @@ LineGraph.prototype._convertXcoordinates = function (datapoints) {
* @private
*/
LineGraph.prototype._convertYcoordinates = function (datapoints, group) {
var extractedData = new Array(datapoints.length);
var xValue, yValue, labelValue;
var toScreen = this.body.util.toScreen;
var axis = this.yAxisLeft;
var svgHeight = Number(this.svg.style.height.replace('px', ''));
if (group.options.yAxisOrientation == 'right') {
axis = this.yAxisRight;
}
for (var i = 0; i < datapoints.length; i++) {
labelValue = datapoints[i].label ? datapoints[i].label : null;
xValue = toScreen(datapoints[i].x) + this.props.width;
yValue = Math.round(axis.convertValue(datapoints[i].y));
extractedData[i] = {x: xValue, y: yValue, label: labelValue};
datapoints[i].screen_y = Math.round(axis.convertValue(datapoints[i].y));
}
group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0)));
return extractedData;
};

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

@ -26,8 +26,8 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
if (group.visible === true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] === true)) {
for (j = 0; j < processedGroupData[groupIds[i]].length; j++) {
combinedData.push({
x: processedGroupData[groupIds[i]][j].x,
y: processedGroupData[groupIds[i]][j].y,
screen_x: processedGroupData[groupIds[i]][j].screen_x,
screen_y: processedGroupData[groupIds[i]][j].screen_y,
groupId: groupIds[i],
label: processedGroupData[groupIds[i]][j].label
});
@ -41,11 +41,11 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
// sort by time and by group
combinedData.sort(function (a, b) {
if (a.x === b.x) {
if (a.screen_x === b.screen_x) {
return a.groupId < b.groupId ? -1 : 1;
}
else {
return a.x - b.x;
return a.screen_x - b.screen_x;
}
});
@ -57,29 +57,29 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
group = framework.groups[combinedData[i].groupId];
var minWidth = 0.1 * group.options.barChart.width;
key = combinedData[i].x;
key = combinedData[i].screen_x;
var heightOffset = 0;
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));}
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].x - key);}
if (prevKey > 0) {coreDistance = Math.min(coreDistance,Math.abs(combinedData[prevKey].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;
if (group.options.stack === true) {
if (combinedData[i].y < group.zeroPosition) {
heightOffset = intersections[key].accumulatedNegative;
intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].y;
intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].screen_y;
}
else {
heightOffset = intersections[key].accumulatedPositive;
intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].y;
intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].screen_y;
}
}
else if (group.options.barChart.sideBySide === true) {
@ -89,12 +89,12 @@ Bargraph.draw = function (groupIds, processedGroupData, framework) {
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 + ' vis-bar', framework.svgElements, framework.svg, group.style);
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 = {
x:combinedData[i].x,
y:combinedData[i].y - heightOffset,
screen_x:combinedData[i].screen_x,
screen_y:combinedData[i].screen_y - heightOffset,
groupId: combinedData[i].groupId,
label: combinedData[i].label,
};
@ -116,16 +116,16 @@ Bargraph._getDataIntersections = function (intersections, combinedData) {
var coreDistance;
for (var i = 0; i < combinedData.length; i++) {
if (i + 1 < combinedData.length) {
coreDistance = Math.abs(combinedData[i + 1].x - combinedData[i].x);
coreDistance = Math.abs(combinedData[i + 1].screen_x - combinedData[i].screen_x);
}
if (i > 0) {
coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].x - combinedData[i].x));
coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].screen_x - combinedData[i].screen_x));
}
if (coreDistance === 0) {
if (intersections[combinedData[i].x] === undefined) {
intersections[combinedData[i].x] = {amount: 0, resolved: 0, accumulatedPositive: 0, accumulatedNegative: 0};
if (intersections[combinedData[i].screen_x] === undefined) {
intersections[combinedData[i].screen_x] = {amount: 0, resolved: 0, accumulatedPositive: 0, accumulatedNegative: 0};
}
intersections[combinedData[i].x].amount += 1;
intersections[combinedData[i].screen_x].amount += 1;
}
}
};
@ -172,11 +172,11 @@ Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupL
if (combinedData.length > 0) {
// sort by time and by group
combinedData.sort(function (a, b) {
if (a.x === b.x) {
if (a.screen_x === b.screen_x) {
return a.groupId < b.groupId ? -1 : 1;
}
else {
return a.x - b.x;
return a.screen_x - b.screen_x;
}
});
var intersections = {};
@ -190,20 +190,20 @@ Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupL
Bargraph._getStackedYRange = function (intersections, combinedData) {
var key;
var yMin = combinedData[0].y;
var yMax = combinedData[0].y;
var yMin = combinedData[0].screen_y;
var yMax = combinedData[0].screen_y;
for (var i = 0; i < combinedData.length; i++) {
key = combinedData[i].x;
key = combinedData[i].screen_x;
if (intersections[key] === undefined) {
yMin = yMin > combinedData[i].y ? combinedData[i].y : yMin;
yMax = yMax < combinedData[i].y ? combinedData[i].y : yMax;
yMin = yMin > combinedData[i].screen_y ? combinedData[i].screen_y : yMin;
yMax = yMax < combinedData[i].screen_y ? combinedData[i].screen_y : yMax;
}
else {
if (combinedData[i].y < 0) {
intersections[key].accumulatedNegative += combinedData[i].y;
if (combinedData[i].screen_y < 0) {
intersections[key].accumulatedNegative += combinedData[i].screen_y;
}
else {
intersections[key].accumulatedPositive += combinedData[i].y;
intersections[key].accumulatedPositive += combinedData[i].screen_y;
}
}
}

+ 26
- 20
lib/timeline/component/graph2d_types/line.js View File

@ -114,7 +114,7 @@ Line._catmullRomUniform = function (data) {
// catmull rom
var p0, p1, p2, p3, bp1, bp2;
var d = [];
d.push( [ Math.round(data[0].x) , Math.round(data[0].y) ]);
d.push( [ Math.round(data[0].screen_x) , Math.round(data[0].screen_y) ]);
var normalization = 1 / 6;
var length = data.length;
for (var i = 0; i < length - 1; i++) {
@ -132,13 +132,19 @@ Line._catmullRomUniform = function (data) {
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = {x: ((-p0.x + 6 * p1.x + p2.x) * normalization), y: ((-p0.y + 6 * p1.y + p2.y) * normalization)};
bp2 = {x: (( p1.x + 6 * p2.x - p3.x) * normalization), y: (( p1.y + 6 * p2.y - p3.y) * normalization)};
bp1 = {
screen_x: ((-p0.screen_x + 6 * p1.screen_x + p2.screen_x) * normalization),
screen_y: ((-p0.screen_y + 6 * p1.screen_y + p2.screen_y) * normalization)
};
bp2 = {
screen_x: (( p1.screen_x + 6 * p2.screen_x - p3.screen_x) * normalization),
screen_y: (( p1.screen_y + 6 * p2.screen_y - p3.screen_y) * normalization)
};
// bp0 = { x: p2.x, y: p2.y };
d.push( [ bp1.x , bp1.y ]);
d.push( [ bp2.x , bp2.y ]);
d.push( [ p2.x , p2.y ]);
d.push( [ bp1.screen_x , bp1.screen_y ]);
d.push( [ bp2.screen_x , bp2.screen_y ]);
d.push( [ p2.screen_x , p2.screen_y ]);
}
return d;
@ -164,7 +170,7 @@ Line._catmullRom = function (data, group) {
var p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
var d = [];
d.push( [ Math.round(data[0].x) , Math.round(data[0].y) ]);
d.push( [ Math.round(data[0].screen_x) , Math.round(data[0].screen_y) ]);
var length = data.length;
for (var i = 0; i < length - 1; i++) {
@ -173,9 +179,9 @@ Line._catmullRom = function (data, group) {
p2 = data[i + 1];
p3 = (i + 2 < length) ? data[i + 2] : p2;
d1 = Math.sqrt(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2));
d2 = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
d3 = Math.sqrt(Math.pow(p2.x - p3.x, 2) + Math.pow(p2.y - p3.y, 2));
d1 = Math.sqrt(Math.pow(p0.screen_x - p1.screen_x, 2) + Math.pow(p0.screen_y - p1.screen_y, 2));
d2 = Math.sqrt(Math.pow(p1.screen_x - p2.screen_x, 2) + Math.pow(p1.screen_y - p2.screen_y, 2));
d3 = Math.sqrt(Math.pow(p2.screen_x - p3.screen_x, 2) + Math.pow(p2.screen_y - p3.screen_y, 2));
// Catmull-Rom to Cubic Bezier conversion matrix
@ -206,24 +212,24 @@ Line._catmullRom = function (data, group) {
}
bp1 = {
x: ((-d2pow2A * p0.x + A * p1.x + d1pow2A * p2.x) * N),
y: ((-d2pow2A * p0.y + A * p1.y + d1pow2A * p2.y) * N)
screen_x: ((-d2pow2A * p0.screen_x + A * p1.screen_x + d1pow2A * p2.screen_x) * N),
screen_y: ((-d2pow2A * p0.screen_y + A * p1.screen_y + d1pow2A * p2.screen_y) * N)
};
bp2 = {
x: (( d3pow2A * p1.x + B * p2.x - d2pow2A * p3.x) * M),
y: (( d3pow2A * p1.y + B * p2.y - d2pow2A * p3.y) * M)
screen_x: (( d3pow2A * p1.screen_x + B * p2.screen_x - d2pow2A * p3.screen_x) * M),
screen_y: (( d3pow2A * p1.screen_y + B * p2.screen_y - d2pow2A * p3.screen_y) * M)
};
if (bp1.x == 0 && bp1.y == 0) {
if (bp1.screen_x == 0 && bp1.screen_y == 0) {
bp1 = p1;
}
if (bp2.x == 0 && bp2.y == 0) {
if (bp2.screen_x == 0 && bp2.screen_y == 0) {
bp2 = p2;
}
d.push( [ bp1.x , bp1.y ]);
d.push( [ bp2.x , bp2.y ]);
d.push( [ p2.x , p2.y ]);
d.push( [ bp1.screen_x , bp1.screen_y ]);
d.push( [ bp2.screen_x , bp2.screen_y ]);
d.push( [ p2.screen_x , p2.screen_y ]);
}
return d;
@ -240,7 +246,7 @@ Line._linear = function (data) {
// linear
var d = [];
for (var i = 0; i < data.length; i++) {
d.push([ data[i].x , data[i].y ]);
d.push([ data[i].screen_x , data[i].screen_y ]);
}
return d;
};

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

@ -19,12 +19,12 @@ Points.draw = function (dataset, group, framework, offset) {
for (var i = 0; i < dataset.length; i++) {
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);
DOMutil.drawPoint(dataset[i].screen_x + offset, dataset[i].screen_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);
DOMutil.drawPoint(dataset[i].screen_x + offset, dataset[i].screen_y, getGroupTemplate(callbackResult), framework.svgElements, framework.svg, dataset[i].label);
}
}
}

Loading…
Cancel
Save