|
@ -838,8 +838,12 @@ Graph3d.prototype.redraw = function() { |
|
|
else if (this.style === Graph3d.STYLE.LINE) { |
|
|
else if (this.style === Graph3d.STYLE.LINE) { |
|
|
this._redrawDataLine(); |
|
|
this._redrawDataLine(); |
|
|
} |
|
|
} |
|
|
else if (this.style === Graph3d.STYLE.BAR || |
|
|
|
|
|
this.style === Graph3d.STYLE.BARCOLOR || |
|
|
|
|
|
|
|
|
else if (this.style === Graph3d.STYLE.BAR) { |
|
|
|
|
|
|
|
|
|
|
|
// Pass a method reference here
|
|
|
|
|
|
this._redrawDataGraph(Graph3d.prototype._redrawBarGraphPoint); |
|
|
|
|
|
|
|
|
|
|
|
} else if (this.style === Graph3d.STYLE.BARCOLOR || |
|
|
this.style === Graph3d.STYLE.BARSIZE) { |
|
|
this.style === Graph3d.STYLE.BARSIZE) { |
|
|
this._redrawDataBar(); |
|
|
this._redrawDataBar(); |
|
|
} |
|
|
} |
|
@ -1565,125 +1569,131 @@ Graph3d.prototype._redrawDataDot = function() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Draw all datapoints for currently selected graph style. |
|
|
|
|
|
|
|
|
* Draw a bar element in the view with the given properties. |
|
|
*/ |
|
|
*/ |
|
|
Graph3d.prototype._redrawDataBar = function() { |
|
|
|
|
|
var ctx = this._getContext(); |
|
|
|
|
|
|
|
|
Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borderColor) { |
|
|
var i, j, surface, corners; |
|
|
var i, j, surface, corners; |
|
|
|
|
|
|
|
|
if (this.dataPoints === undefined || this.dataPoints.length <= 0) |
|
|
|
|
|
return; // TODO: throw exception?
|
|
|
|
|
|
|
|
|
// calculate all corner points
|
|
|
|
|
|
var me = this; |
|
|
|
|
|
var point3d = point.point; |
|
|
|
|
|
var top = [ |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} |
|
|
|
|
|
]; |
|
|
|
|
|
var bottom = [ |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
// calculate screen location of the points
|
|
|
|
|
|
top.forEach(function (obj) { |
|
|
|
|
|
obj.screen = me._convert3Dto2D(obj.point); |
|
|
|
|
|
}); |
|
|
|
|
|
bottom.forEach(function (obj) { |
|
|
|
|
|
obj.screen = me._convert3Dto2D(obj.point); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// create five sides, calculate both corner points and center points
|
|
|
|
|
|
var surfaces = [ |
|
|
|
|
|
{corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, |
|
|
|
|
|
{corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, |
|
|
|
|
|
{corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, |
|
|
|
|
|
{corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, |
|
|
|
|
|
{corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} |
|
|
|
|
|
]; |
|
|
|
|
|
point.surfaces = surfaces; |
|
|
|
|
|
|
|
|
|
|
|
// calculate the distance of each of the surface centers to the camera
|
|
|
|
|
|
for (j = 0; j < surfaces.length; j++) { |
|
|
|
|
|
surface = surfaces[j]; |
|
|
|
|
|
var transCenter = this._convertPointToTranslation(surface.center); |
|
|
|
|
|
surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; |
|
|
|
|
|
// TODO: this dept calculation doesn't work 100% of the cases due to perspective,
|
|
|
|
|
|
// but the current solution is fast/simple and works in 99.9% of all cases
|
|
|
|
|
|
// the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// order the surfaces by their (translated) depth
|
|
|
|
|
|
surfaces.sort(function (a, b) { |
|
|
|
|
|
var diff = b.dist - a.dist; |
|
|
|
|
|
if (diff) return diff; |
|
|
|
|
|
|
|
|
|
|
|
// if equal depth, sort the top surface last
|
|
|
|
|
|
if (a.corners === top) return 1; |
|
|
|
|
|
if (b.corners === top) return -1; |
|
|
|
|
|
|
|
|
|
|
|
// both are equal
|
|
|
|
|
|
return 0; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// draw the ordered surfaces
|
|
|
|
|
|
ctx.lineWidth = this._getStrokeWidth(point); |
|
|
|
|
|
ctx.strokeStyle = borderColor; |
|
|
|
|
|
ctx.fillStyle = color; |
|
|
|
|
|
// NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
|
|
|
|
|
|
for (j = 2; j < surfaces.length; j++) { |
|
|
|
|
|
surface = surfaces[j]; |
|
|
|
|
|
corners = surface.corners; |
|
|
|
|
|
ctx.beginPath(); |
|
|
|
|
|
ctx.moveTo(corners[3].screen.x, corners[3].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[0].screen.x, corners[0].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[1].screen.x, corners[1].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[2].screen.x, corners[2].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[3].screen.x, corners[3].screen.y); |
|
|
|
|
|
ctx.fill(); |
|
|
|
|
|
ctx.stroke(); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
this._calcTranslations(this.dataPoints); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Draw single datapoint for graph style 'Bar'. |
|
|
|
|
|
*/ |
|
|
|
|
|
Graph3d.prototype._redrawBarGraphPoint = function(ctx, point) { |
|
|
|
|
|
var i, j, surface, corners; |
|
|
|
|
|
|
|
|
ctx.lineJoin = 'round'; |
|
|
ctx.lineJoin = 'round'; |
|
|
ctx.lineCap = 'round'; |
|
|
ctx.lineCap = 'round'; |
|
|
|
|
|
|
|
|
// draw the datapoints as bars
|
|
|
|
|
|
var xWidth = this.xBarWidth / 2; |
|
|
var xWidth = this.xBarWidth / 2; |
|
|
var yWidth = this.yBarWidth / 2; |
|
|
var yWidth = this.yBarWidth / 2; |
|
|
for (i = 0; i < this.dataPoints.length; i++) { |
|
|
|
|
|
var point = this.dataPoints[i]; |
|
|
|
|
|
|
|
|
|
|
|
// determine color
|
|
|
|
|
|
var hue, color, borderColor; |
|
|
|
|
|
if (this.style === Graph3d.STYLE.BARCOLOR ) { |
|
|
|
|
|
// calculate the color based on the value
|
|
|
|
|
|
hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240; |
|
|
|
|
|
color = this._hsv2rgb(hue, 1, 1); |
|
|
|
|
|
borderColor = this._hsv2rgb(hue, 1, 0.8); |
|
|
|
|
|
} |
|
|
|
|
|
else if (this.style === Graph3d.STYLE.BARSIZE) { |
|
|
|
|
|
color = this.dataColor.fill; |
|
|
|
|
|
borderColor = this.dataColor.stroke; |
|
|
|
|
|
} |
|
|
|
|
|
else { |
|
|
|
|
|
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
|
|
|
|
|
|
hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; |
|
|
|
|
|
color = this._hsv2rgb(hue, 1, 1); |
|
|
|
|
|
borderColor = this._hsv2rgb(hue, 1, 0.8); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// calculate size for the bar
|
|
|
|
|
|
if (this.style === Graph3d.STYLE.BARSIZE) { |
|
|
|
|
|
xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); |
|
|
|
|
|
yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// calculate all corner points
|
|
|
|
|
|
var me = this; |
|
|
|
|
|
var point3d = point.point; |
|
|
|
|
|
var top = [ |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)}, |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)} |
|
|
|
|
|
]; |
|
|
|
|
|
var bottom = [ |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)}, |
|
|
|
|
|
{point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)} |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
// determine color
|
|
|
|
|
|
var hue, color, borderColor; |
|
|
|
|
|
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
|
|
|
|
|
|
hue = (1 - (point.point.z - this.zMin) * this.scale.z / this.verticalRatio) * 240; |
|
|
|
|
|
color = this._hsv2rgb(hue, 1, 1); |
|
|
|
|
|
borderColor = this._hsv2rgb(hue, 1, 0.8); |
|
|
|
|
|
|
|
|
// calculate screen location of the points
|
|
|
|
|
|
top.forEach(function (obj) { |
|
|
|
|
|
obj.screen = me._convert3Dto2D(obj.point); |
|
|
|
|
|
}); |
|
|
|
|
|
bottom.forEach(function (obj) { |
|
|
|
|
|
obj.screen = me._convert3Dto2D(obj.point); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
this._redrawBar(ctx, point, xWidth, yWidth, color, borderColor); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// create five sides, calculate both corner points and center points
|
|
|
|
|
|
var surfaces = [ |
|
|
|
|
|
{corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)}, |
|
|
|
|
|
{corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)}, |
|
|
|
|
|
{corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)}, |
|
|
|
|
|
{corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)}, |
|
|
|
|
|
{corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)} |
|
|
|
|
|
]; |
|
|
|
|
|
point.surfaces = surfaces; |
|
|
|
|
|
|
|
|
|
|
|
// calculate the distance of each of the surface centers to the camera
|
|
|
|
|
|
for (j = 0; j < surfaces.length; j++) { |
|
|
|
|
|
surface = surfaces[j]; |
|
|
|
|
|
var transCenter = this._convertPointToTranslation(surface.center); |
|
|
|
|
|
surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z; |
|
|
|
|
|
// TODO: this dept calculation doesn't work 100% of the cases due to perspective,
|
|
|
|
|
|
// but the current solution is fast/simple and works in 99.9% of all cases
|
|
|
|
|
|
// the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Draw all datapoints for currently selected graph style. |
|
|
|
|
|
* |
|
|
|
|
|
* @param pointDrawMethod - method reference to draw a point in a specific graph style. |
|
|
|
|
|
*/ |
|
|
|
|
|
Graph3d.prototype._redrawDataGraph = function(pointDrawMethod) { |
|
|
|
|
|
var ctx = this._getContext(); |
|
|
|
|
|
var i; |
|
|
|
|
|
|
|
|
// order the surfaces by their (translated) depth
|
|
|
|
|
|
surfaces.sort(function (a, b) { |
|
|
|
|
|
var diff = b.dist - a.dist; |
|
|
|
|
|
if (diff) return diff; |
|
|
|
|
|
|
|
|
if (this.dataPoints === undefined || this.dataPoints.length <= 0) |
|
|
|
|
|
return; // TODO: throw exception?
|
|
|
|
|
|
|
|
|
// if equal depth, sort the top surface last
|
|
|
|
|
|
if (a.corners === top) return 1; |
|
|
|
|
|
if (b.corners === top) return -1; |
|
|
|
|
|
|
|
|
this._calcTranslations(this.dataPoints); |
|
|
|
|
|
|
|
|
// both are equal
|
|
|
|
|
|
return 0; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
for (i = 0; i < this.dataPoints.length; i++) { |
|
|
|
|
|
var point = this.dataPoints[i]; |
|
|
|
|
|
|
|
|
// draw the ordered surfaces
|
|
|
|
|
|
ctx.lineWidth = this._getStrokeWidth(point); |
|
|
|
|
|
ctx.strokeStyle = borderColor; |
|
|
|
|
|
ctx.fillStyle = color; |
|
|
|
|
|
// NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
|
|
|
|
|
|
for (j = 2; j < surfaces.length; j++) { |
|
|
|
|
|
surface = surfaces[j]; |
|
|
|
|
|
corners = surface.corners; |
|
|
|
|
|
ctx.beginPath(); |
|
|
|
|
|
ctx.moveTo(corners[3].screen.x, corners[3].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[0].screen.x, corners[0].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[1].screen.x, corners[1].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[2].screen.x, corners[2].screen.y); |
|
|
|
|
|
ctx.lineTo(corners[3].screen.x, corners[3].screen.y); |
|
|
|
|
|
ctx.fill(); |
|
|
|
|
|
ctx.stroke(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Using call() ensures that the correct context is used
|
|
|
|
|
|
pointDrawMethod.call(this, ctx, point); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -1710,6 +1720,8 @@ Graph3d.prototype._redrawDataBar = function() { |
|
|
for (i = 0; i < this.dataPoints.length; i++) { |
|
|
for (i = 0; i < this.dataPoints.length; i++) { |
|
|
var point = this.dataPoints[i]; |
|
|
var point = this.dataPoints[i]; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: Remove code for style `Bar` here - it has been refactored to separate routine
|
|
|
|
|
|
|
|
|
// determine color
|
|
|
// determine color
|
|
|
var hue, color, borderColor; |
|
|
var hue, color, borderColor; |
|
|
if (this.style === Graph3d.STYLE.BARCOLOR ) { |
|
|
if (this.style === Graph3d.STYLE.BARCOLOR ) { |
|
|