|  |  | @ -831,21 +831,34 @@ Graph3d.prototype.redraw = function() { | 
			
		
	
		
			
				
					|  |  |  | this._redrawClear(); | 
			
		
	
		
			
				
					|  |  |  | this._redrawAxis(); | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | if (this.style === Graph3d.STYLE.GRID || | 
			
		
	
		
			
				
					|  |  |  | this.style === Graph3d.STYLE.SURFACE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataGrid(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | else if (this.style === Graph3d.STYLE.LINE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataLine(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | else if (this.style === Graph3d.STYLE.BAR || | 
			
		
	
		
			
				
					|  |  |  | this.style === Graph3d.STYLE.BARCOLOR || | 
			
		
	
		
			
				
					|  |  |  | this.style === Graph3d.STYLE.BARSIZE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataBar(); | 
			
		
	
		
			
				
					|  |  |  | var pointDrawingMethod = undefined; | 
			
		
	
		
			
				
					|  |  |  | switch (this.style) { | 
			
		
	
		
			
				
					|  |  |  | case Graph3d.STYLE.BAR: | 
			
		
	
		
			
				
					|  |  |  | pointDrawingMethod = Graph3d.prototype._redrawBarGraphPoint; | 
			
		
	
		
			
				
					|  |  |  | break; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | else { | 
			
		
	
		
			
				
					|  |  |  | // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataDot(); | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | if (pointDrawingMethod !== undefined) { | 
			
		
	
		
			
				
					|  |  |  | // Use generic drawing loop | 
			
		
	
		
			
				
					|  |  |  | // Pass the method reference here | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataGraph(pointDrawingMethod); | 
			
		
	
		
			
				
					|  |  |  | } else { | 
			
		
	
		
			
				
					|  |  |  | // Use the old style drawing methods | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | if (this.style === Graph3d.STYLE.GRID || | 
			
		
	
		
			
				
					|  |  |  | this.style === Graph3d.STYLE.SURFACE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataGrid(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | else if (this.style === Graph3d.STYLE.LINE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataLine(); | 
			
		
	
		
			
				
					|  |  |  | } else if (this.style === Graph3d.STYLE.BARCOLOR || | 
			
		
	
		
			
				
					|  |  |  | this.style === Graph3d.STYLE.BARSIZE) { | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataBar(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | else { | 
			
		
	
		
			
				
					|  |  |  | // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE | 
			
		
	
		
			
				
					|  |  |  | this._redrawDataDot(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | this._redrawInfo(); | 
			
		
	
	
		
			
				
					|  |  | @ -1563,6 +1576,137 @@ Graph3d.prototype._redrawDataDot = function() { | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  | * Draw a bar element in the view with the given properties. | 
			
		
	
		
			
				
					|  |  |  | */ | 
			
		
	
		
			
				
					|  |  |  | Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borderColor) { | 
			
		
	
		
			
				
					|  |  |  | var i, j, surface, corners; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | // 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(); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  | * Draw single datapoint for graph style 'Bar'. | 
			
		
	
		
			
				
					|  |  |  | */ | 
			
		
	
		
			
				
					|  |  |  | Graph3d.prototype._redrawBarGraphPoint = function(ctx, point) { | 
			
		
	
		
			
				
					|  |  |  | var i, j, surface, corners; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | ctx.lineJoin = 'round'; | 
			
		
	
		
			
				
					|  |  |  | ctx.lineCap = 'round'; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | var xWidth = this.xBarWidth / 2; | 
			
		
	
		
			
				
					|  |  |  | var yWidth = this.yBarWidth / 2; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | // 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); | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | this._redrawBar(ctx, point, xWidth, yWidth, color, borderColor); | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  | * 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; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | if (this.dataPoints === undefined || this.dataPoints.length <= 0) | 
			
		
	
		
			
				
					|  |  |  | return;  // TODO: throw exception? | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | this._calcTranslations(this.dataPoints); | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | for (i = 0; i < this.dataPoints.length; i++) { | 
			
		
	
		
			
				
					|  |  |  | var point = this.dataPoints[i]; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | // Using call() ensures that the correct context is used | 
			
		
	
		
			
				
					|  |  |  | pointDrawMethod.call(this, ctx, point); | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  | * Draw all datapoints as bars. | 
			
		
	
		
			
				
					|  |  |  | * This function can be used when the style is 'bar', 'bar-color', or 'bar-size' | 
			
		
	
	
		
			
				
					|  |  | @ -1585,6 +1729,8 @@ Graph3d.prototype._redrawDataBar = function() { | 
			
		
	
		
			
				
					|  |  |  | for (i = 0; i < this.dataPoints.length; i++) { | 
			
		
	
		
			
				
					|  |  |  | var point = this.dataPoints[i]; | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | // TODO: Remove code for style `Bar` here - it has been refactored to separate routine | 
			
		
	
		
			
				
					|  |  |  |  | 
			
		
	
		
			
				
					|  |  |  | // determine color | 
			
		
	
		
			
				
					|  |  |  | var hue, color, borderColor; | 
			
		
	
		
			
				
					|  |  |  | if (this.style === Graph3d.STYLE.BARCOLOR ) { | 
			
		
	
	
		
			
				
					|  |  |  |