@ -58,6 +58,8 @@ function Graph3d(container, data, options) {
this . animationPreload = false ;
this . camera = new Camera ( ) ;
this . camera . setArmRotation ( 1.0 , 0.5 ) ;
this . camera . setArmLength ( 1.7 ) ;
this . eye = new Point3d ( 0 , 0 , - 1 ) ; // TODO: set eye.z about 3/4 of the width of the window?
this . dataTable = null ; // The original data table
@ -85,11 +87,14 @@ function Graph3d(container, data, options) {
this . yBarWidth = 1 ;
// TODO: customize axis range
// constants
this . colorAxis = '#4D4D4D' ;
this . colorGrid = '#D3D3D3' ;
this . colorDot = '#7DC1FF' ;
this . colorDotBorder = '#3267D2' ;
// colors
this . axisColor = '#4D4D4D' ;
this . gridColor = '#D3D3D3' ;
this . dataColor = {
fill : '#7DC1FF' ,
stroke : '#3267D2' ,
strokeWidth : 1 // px
} ;
// create a frame and canvas
this . create ( ) ;
@ -823,21 +828,21 @@ Graph3d.prototype.setOptions = function (options) {
if ( options !== undefined ) {
// retrieve parameter values
if ( options . width !== undefined ) this . width = options . width ;
if ( options . height !== undefined ) this . height = options . height ;
if ( options . width !== undefined ) this . width = options . width ;
if ( options . height !== undefined ) this . height = options . height ;
if ( options . xCenter !== undefined ) this . defaultXCenter = options . xCenter ;
if ( options . yCenter !== undefined ) this . defaultYCenter = options . yCenter ;
if ( options . xCenter !== undefined ) this . defaultXCenter = options . xCenter ;
if ( options . yCenter !== undefined ) this . defaultYCenter = options . yCenter ;
if ( options . filterLabel !== undefined ) this . filterLabel = options . filterLabel ;
if ( options . legendLabel !== undefined ) this . legendLabel = options . legendLabel ;
if ( options . xLabel !== undefined ) this . xLabel = options . xLabel ;
if ( options . yLabel !== undefined ) this . yLabel = options . yLabel ;
if ( options . zLabel !== undefined ) this . zLabel = options . zLabel ;
if ( options . filterLabel !== undefined ) this . filterLabel = options . filterLabel ;
if ( options . legendLabel !== undefined ) this . legendLabel = options . legendLabel ;
if ( options . xLabel !== undefined ) this . xLabel = options . xLabel ;
if ( options . yLabel !== undefined ) this . yLabel = options . yLabel ;
if ( options . zLabel !== undefined ) this . zLabel = options . zLabel ;
if ( options . xValueLabel !== undefined ) this . xValueLabel = options . xValueLabel ;
if ( options . yValueLabel !== undefined ) this . yValueLabel = options . yValueLabel ;
if ( options . zValueLabel !== undefined ) this . zValueLabel = options . zValueLabel ;
if ( options . xValueLabel !== undefined ) this . xValueLabel = options . xValueLabel ;
if ( options . yValueLabel !== undefined ) this . yValueLabel = options . yValueLabel ;
if ( options . zValueLabel !== undefined ) this . zValueLabel = options . zValueLabel ;
if ( options . style !== undefined ) {
var styleNumber = this . _getStyleNumber ( options . style ) ;
@ -878,14 +883,30 @@ Graph3d.prototype.setOptions = function (options) {
this . camera . setArmRotation ( cameraPosition . horizontal , cameraPosition . vertical ) ;
this . camera . setArmLength ( cameraPosition . distance ) ;
}
else {
this . camera . setArmRotation ( 1.0 , 0.5 ) ;
this . camera . setArmLength ( 1.7 ) ;
// colors
if ( options . axisColor !== undefined ) this . axisColor = options . axisColor ;
if ( options . gridColor !== undefined ) this . gridColor = options . gridColor ;
if ( options . dataColor ) {
if ( typeof options . dataColor === 'string' ) {
this . dataColor . fill = options . dataColor ;
this . dataColor . stroke = options . dataColor ;
}
else {
if ( options . dataColor . fill ) {
this . dataColor . fill = options . dataColor . fill ;
}
if ( options . dataColor . stroke ) {
this . dataColor . stroke = options . dataColor . stroke ;
}
if ( options . dataColor . strokeWidth !== undefined ) {
this . dataColor . strokeWidth = options . dataColor . strokeWidth ;
}
}
}
this . _setBackgroundColor ( options . backgroundColor ) ;
}
this . _setBackgroundColor ( options && options . backgroundColor ) ;
this . setSize ( this . width , this . height ) ;
// re-load the data
@ -996,14 +1017,14 @@ Graph3d.prototype._redrawLegend = function() {
ctx . stroke ( ) ;
}
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . strokeRect ( left , top , widthMax , height ) ;
}
if ( this . style === Graph3d . STYLE . DOTSIZE ) {
// draw border around color bar
ctx . strokeStyle = this . colorAxis ;
ctx . fillStyle = this . colorDot ;
ctx . strokeStyle = this . axisColor ;
ctx . fillStyle = this . dataColor . fill ;
ctx . beginPath ( ) ;
ctx . moveTo ( left , top ) ;
ctx . lineTo ( right , top ) ;
@ -1033,7 +1054,7 @@ Graph3d.prototype._redrawLegend = function() {
ctx . textAlign = 'right' ;
ctx . textBaseline = 'middle' ;
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( step . getCurrent ( ) , left - 2 * gridLineLen , y ) ;
step . next ( ) ;
@ -1149,7 +1170,7 @@ Graph3d.prototype._redrawAxis = function() {
if ( this . showGrid ) {
from = this . _convert3Dto2D ( new Point3d ( x , this . yMin , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( x , this . yMax , this . zMin ) ) ;
ctx . strokeStyle = this . colorGrid ;
ctx . strokeStyle = this . gridColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1158,7 +1179,7 @@ Graph3d.prototype._redrawAxis = function() {
else {
from = this . _convert3Dto2D ( new Point3d ( x , this . yMin , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( x , this . yMin + gridLenX , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1166,7 +1187,7 @@ Graph3d.prototype._redrawAxis = function() {
from = this . _convert3Dto2D ( new Point3d ( x , this . yMax , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( x , this . yMax - gridLenX , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1188,7 +1209,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . textAlign = 'left' ;
ctx . textBaseline = 'middle' ;
}
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( ' ' + this . xValueLabel ( step . getCurrent ( ) ) + ' ' , text . x , text . y ) ;
step . next ( ) ;
@ -1206,7 +1227,7 @@ Graph3d.prototype._redrawAxis = function() {
if ( this . showGrid ) {
from = this . _convert3Dto2D ( new Point3d ( this . xMin , step . getCurrent ( ) , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( this . xMax , step . getCurrent ( ) , this . zMin ) ) ;
ctx . strokeStyle = this . colorGrid ;
ctx . strokeStyle = this . gridColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1215,7 +1236,7 @@ Graph3d.prototype._redrawAxis = function() {
else {
from = this . _convert3Dto2D ( new Point3d ( this . xMin , step . getCurrent ( ) , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( this . xMin + gridLenY , step . getCurrent ( ) , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1223,7 +1244,7 @@ Graph3d.prototype._redrawAxis = function() {
from = this . _convert3Dto2D ( new Point3d ( this . xMax , step . getCurrent ( ) , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( this . xMax - gridLenY , step . getCurrent ( ) , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1245,7 +1266,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . textAlign = 'left' ;
ctx . textBaseline = 'middle' ;
}
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( ' ' + this . yValueLabel ( step . getCurrent ( ) ) + ' ' , text . x , text . y ) ;
step . next ( ) ;
@ -1264,7 +1285,7 @@ Graph3d.prototype._redrawAxis = function() {
while ( ! step . end ( ) ) {
// TODO: make z-grid lines really 3d?
from = this . _convert3Dto2D ( new Point3d ( xText , yText , step . getCurrent ( ) ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( from . x - textMargin , from . y ) ;
@ -1272,7 +1293,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . textAlign = 'right' ;
ctx . textBaseline = 'middle' ;
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( this . zValueLabel ( step . getCurrent ( ) ) + ' ' , from . x - 5 , from . y ) ;
step . next ( ) ;
@ -1280,7 +1301,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . lineWidth = 1 ;
from = this . _convert3Dto2D ( new Point3d ( xText , yText , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( xText , yText , this . zMax ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1291,7 +1312,7 @@ Graph3d.prototype._redrawAxis = function() {
// line at yMin
xMin2d = this . _convert3Dto2D ( new Point3d ( this . xMin , this . yMin , this . zMin ) ) ;
xMax2d = this . _convert3Dto2D ( new Point3d ( this . xMax , this . yMin , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( xMin2d . x , xMin2d . y ) ;
ctx . lineTo ( xMax2d . x , xMax2d . y ) ;
@ -1299,7 +1320,7 @@ Graph3d.prototype._redrawAxis = function() {
// line at ymax
xMin2d = this . _convert3Dto2D ( new Point3d ( this . xMin , this . yMax , this . zMin ) ) ;
xMax2d = this . _convert3Dto2D ( new Point3d ( this . xMax , this . yMax , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( xMin2d . x , xMin2d . y ) ;
ctx . lineTo ( xMax2d . x , xMax2d . y ) ;
@ -1310,7 +1331,7 @@ Graph3d.prototype._redrawAxis = function() {
// line at xMin
from = this . _convert3Dto2D ( new Point3d ( this . xMin , this . yMin , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( this . xMin , this . yMax , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1318,7 +1339,7 @@ Graph3d.prototype._redrawAxis = function() {
// line at xMax
from = this . _convert3Dto2D ( new Point3d ( this . xMax , this . yMin , this . zMin ) ) ;
to = this . _convert3Dto2D ( new Point3d ( this . xMax , this . yMax , this . zMin ) ) ;
ctx . strokeStyle = this . colorAxis ;
ctx . strokeStyle = this . axisColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( to . x , to . y ) ;
@ -1343,7 +1364,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . textAlign = 'left' ;
ctx . textBaseline = 'middle' ;
}
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( xLabel , text . x , text . y ) ;
}
@ -1366,7 +1387,7 @@ Graph3d.prototype._redrawAxis = function() {
ctx . textAlign = 'left' ;
ctx . textBaseline = 'middle' ;
}
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( yLabel , text . x , text . y ) ;
}
@ -1380,7 +1401,7 @@ Graph3d.prototype._redrawAxis = function() {
text = this . _convert3Dto2D ( new Point3d ( xText , yText , zText ) ) ;
ctx . textAlign = 'right' ;
ctx . textBaseline = 'middle' ;
ctx . fillStyle = this . colorAxis ;
ctx . fillStyle = this . axisColor ;
ctx . fillText ( zLabel , text . x - offset , text . y ) ;
}
} ;
@ -1425,6 +1446,8 @@ Graph3d.prototype._redrawDataGrid = function() {
topSideVisible , fillStyle , strokeStyle , lineWidth ,
h , s , v , zAvg ;
ctx . lineJoin = 'round' ;
ctx . lineCap = 'round' ;
if ( this . dataPoints === undefined || this . dataPoints . length <= 0 )
return ; // TODO: throw exception?
@ -1488,16 +1511,15 @@ Graph3d.prototype._redrawDataGrid = function() {
else {
v = 1 ;
fillStyle = this . _hsv2rgb ( h , s , v ) ;
strokeStyle = this . colorAxis ;
strokeStyle = this . axisColor ;
}
}
else {
fillStyle = 'gray' ;
strokeStyle = this . colorAxis ;
strokeStyle = this . axisColor ;
}
lineWidth = 0.5 ;
ctx . lineWidth = lineWidth ;
ctx . lineWidth = this . _getStrokeWidth ( point ) ;
ctx . fillStyle = fillStyle ;
ctx . strokeStyle = strokeStyle ;
ctx . beginPath ( ) ;
@ -1517,21 +1539,12 @@ Graph3d.prototype._redrawDataGrid = function() {
right = this . dataPoints [ i ] . pointRight ;
top = this . dataPoints [ i ] . pointTop ;
if ( point !== undefined ) {
if ( this . showPerspective ) {
lineWidth = 2 / - point . trans . z ;
}
else {
lineWidth = 2 * - ( this . eye . z / this . camera . getArmLength ( ) ) ;
}
}
if ( point !== undefined && right !== undefined ) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
zAvg = ( point . point . z + right . point . z ) / 2 ;
h = ( 1 - ( zAvg - this . zMin ) * this . scale . z / this . verticalRatio ) * 240 ;
ctx . lineWidth = lineWidth ;
ctx . lineWidth = this . _getStrokeWidth ( point ) * 2 ;
ctx . strokeStyle = this . _hsv2rgb ( h , 1 , 1 ) ;
ctx . beginPath ( ) ;
ctx . moveTo ( point . screen . x , point . screen . y ) ;
@ -1544,7 +1557,7 @@ Graph3d.prototype._redrawDataGrid = function() {
zAvg = ( point . point . z + top . point . z ) / 2 ;
h = ( 1 - ( zAvg - this . zMin ) * this . scale . z / this . verticalRatio ) * 240 ;
ctx . lineWidth = lineWidth ;
ctx . lineWidth = this . _getStrokeWidth ( point ) * 2 ;
ctx . strokeStyle = this . _hsv2rgb ( h , 1 , 1 ) ;
ctx . beginPath ( ) ;
ctx . moveTo ( point . screen . x , point . screen . y ) ;
@ -1555,6 +1568,18 @@ Graph3d.prototype._redrawDataGrid = function() {
}
} ;
Graph3d . prototype . _getStrokeWidth = function ( point ) {
if ( point !== undefined ) {
if ( this . showPerspective ) {
return 1 / - point . trans . z * this . dataColor . strokeWidth ;
}
else {
return - ( this . eye . z / this . camera . getArmLength ( ) ) * this . dataColor . strokeWidth ;
}
}
return this . dataColor . strokeWidth ;
} ;
/ * *
* Draw all datapoints as dots .
@ -1596,7 +1621,7 @@ Graph3d.prototype._redrawDataDot = function() {
//var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin));
var from = this . _convert3Dto2D ( point . bottom ) ;
ctx . lineWidth = 1 ;
ctx . strokeStyle = this . colorGrid ;
ctx . strokeStyle = this . gridColor ;
ctx . beginPath ( ) ;
ctx . moveTo ( from . x , from . y ) ;
ctx . lineTo ( point . screen . x , point . screen . y ) ;
@ -1631,8 +1656,8 @@ Graph3d.prototype._redrawDataDot = function() {
borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
}
else if ( this . style === Graph3d . STYLE . DOTSIZE ) {
color = this . colorDot ;
borderColor = this . colorDotBorder ;
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
@ -1642,7 +1667,7 @@ Graph3d.prototype._redrawDataDot = function() {
}
// draw the circle
ctx . lineWidth = 1.0 ;
ctx . lineWidth = this . _getStrokeWidth ( point ) ;
ctx . strokeStyle = borderColor ;
ctx . fillStyle = color ;
ctx . beginPath ( ) ;
@ -1682,6 +1707,9 @@ Graph3d.prototype._redrawDataBar = function() {
} ;
this . dataPoints . sort ( sortDepth ) ;
ctx . lineJoin = 'round' ;
ctx . lineCap = 'round' ;
// draw the datapoints as bars
var xWidth = this . xBarWidth / 2 ;
var yWidth = this . yBarWidth / 2 ;
@ -1697,8 +1725,8 @@ Graph3d.prototype._redrawDataBar = function() {
borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
}
else if ( this . style === Graph3d . STYLE . BARSIZE ) {
color = this . colorDot ;
borderColor = this . colorDotBorder ;
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
@ -1771,7 +1799,7 @@ Graph3d.prototype._redrawDataBar = function() {
} ) ;
// draw the ordered surfaces
ctx . lineWidth = 1 ;
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
@ -1816,20 +1844,20 @@ Graph3d.prototype._redrawDataLine = function() {
if ( this . dataPoints . length > 0 ) {
point = this . dataPoints [ 0 ] ;
ctx . lineWidth = 1 ; // TODO: make customizable
ctx . strokeStyle = 'blue' ; // TODO: make customizable
ctx . lineWidth = this . _getStrokeWidth ( point ) ;
ctx . lineJoin = 'round' ;
ctx . lineCap = 'round' ;
ctx . strokeStyle = this . dataColor . stroke ;
ctx . beginPath ( ) ;
ctx . moveTo ( point . screen . x , point . screen . y ) ;
}
// draw the datapoints as colored circles
for ( i = 1 ; i < this . dataPoints . length ; i ++ ) {
point = this . dataPoints [ i ] ;
ctx . lineTo ( point . screen . x , point . screen . y ) ;
}
// draw the datapoints as colored circles
for ( i = 1 ; i < this . dataPoints . length ; i ++ ) {
point = this . dataPoints [ i ] ;
ctx . lineTo ( point . screen . x , point . screen . y ) ;
}
// finish the line
if ( this . dataPoints . length > 0 ) {
// finish the line
ctx . stroke ( ) ;
}
} ;