@ -7,6 +7,7 @@ var Camera = require('./Camera');
var Filter = require ( './Filter' ) ;
var Filter = require ( './Filter' ) ;
var Slider = require ( './Slider' ) ;
var Slider = require ( './Slider' ) ;
var StepNumber = require ( './StepNumber' ) ;
var StepNumber = require ( './StepNumber' ) ;
var Range = require ( './Range' ) ;
var Settings = require ( './Settings' ) ;
var Settings = require ( './Settings' ) ;
@ -15,12 +16,11 @@ Graph3d.STYLE = Settings.STYLE;
/ * *
/ * *
* Following label is used in the settings to describe values which
* should be determined by the code while running , from the current
* data and graph style .
* Following label is used in the settings to describe values which should be
* determined by the code while running , from the current data and graph style .
*
*
* Using 'undefined' directly achieves the same thing , but this is
* more descriptive by describing the intent .
* Using 'undefined' directly achieves the same thing , but this is more
* descriptive by describing the intent .
* /
* /
var autoByDefault = undefined ;
var autoByDefault = undefined ;
@ -28,11 +28,11 @@ var autoByDefault = undefined;
/ * *
/ * *
* Default values for option settings .
* Default values for option settings .
*
*
* These are the values used when a Graph3d instance is initialized
* without custom settings .
* These are the values used when a Graph3d instance is initialized without
* custom settings .
*
*
* If a field is not in this list , a default value of 'autoByDefault'
* is assumed , which is just an alias for 'undefined' .
* If a field is not in this list , a default value of 'autoByDefault' is assumed ,
* which is just an alias for 'undefined' .
* /
* /
var DEFAULTS = {
var DEFAULTS = {
width : '400px' ,
width : '400px' ,
@ -49,11 +49,11 @@ var DEFAULTS = {
showPerspective : true ,
showPerspective : true ,
showShadow : false ,
showShadow : false ,
keepAspectRatio : true ,
keepAspectRatio : true ,
verticalRatio : 0.5 , // 0.1 to 1.0, where 1.0 results in a 'cube'
dotSizeRatio : 0.02 , // size of the dots as a fraction of the graph width
verticalRatio : 0.5 , // 0.1 to 1.0, where 1.0 results in a 'cube'
dotSizeRatio : 0.02 , // size of the dots as a fraction of the graph width
showAnimationControls : autoByDefault ,
showAnimationControls : autoByDefault ,
animationInterval : 1000 , // milliseconds
animationInterval : 1000 , // milliseconds
animationPreload : false ,
animationPreload : false ,
animationAutoStart : autoByDefault ,
animationAutoStart : autoByDefault ,
@ -64,13 +64,13 @@ var DEFAULTS = {
style : Graph3d . STYLE . DOT ,
style : Graph3d . STYLE . DOT ,
tooltip : false ,
tooltip : false ,
showLegend : autoByDefault , // determined by graph style
showLegend : autoByDefault , // determined by graph style
backgroundColor : autoByDefault ,
backgroundColor : autoByDefault ,
dataColor : {
dataColor : {
fill : '#7DC1FF' ,
fill : '#7DC1FF' ,
stroke : '#3267D2' ,
stroke : '#3267D2' ,
strokeWidth : 1 // px
strokeWidth : 1 // px
} ,
} ,
cameraPosition : {
cameraPosition : {
@ -152,9 +152,11 @@ Emitter(Graph3d.prototype);
* Calculate the scaling values , dependent on the range in x , y , and z direction
* Calculate the scaling values , dependent on the range in x , y , and z direction
* /
* /
Graph3d . prototype . _setScale = function ( ) {
Graph3d . prototype . _setScale = function ( ) {
this . scale = new Point3d ( 1 / ( this . xMax - this . xMin ) ,
1 / ( this . yMax - this . yMin ) ,
1 / ( this . zMax - this . zMin ) ) ;
this . scale = new Point3d (
1 / this . xRange . range ( ) ,
1 / this . yRange . range ( ) ,
1 / this . zRange . range ( )
) ;
// keep aspect ration between x and y scale if desired
// keep aspect ration between x and y scale if desired
if ( this . keepAspectRatio ) {
if ( this . keepAspectRatio ) {
@ -173,21 +175,24 @@ Graph3d.prototype._setScale = function() {
// TODO: can this be automated? verticalRatio?
// TODO: can this be automated? verticalRatio?
// determine scale for (optional) value
// determine scale for (optional) value
this . scale . value = 1 / ( this . valueMax - this . valueMin ) ;
if ( this . valueRange !== undefined ) {
this . scale . value = 1 / this . valueRange . range ( ) ;
}
// position the camera arm
// position the camera arm
var xCenter = ( this . xMax + this . xMin ) / 2 * this . scale . x ;
var yCenter = ( this . yMax + this . yMin ) / 2 * this . scale . y ;
var zCenter = ( this . zMax + this . zMin ) / 2 * this . scale . z ;
var xCenter = this . xRange . center ( ) * this . scale . x ;
var yCenter = this . yRange . center ( ) * this . scale . y ;
var zCenter = this . zRange . center ( ) * this . scale . z ;
this . camera . setArmLocation ( xCenter , yCenter , zCenter ) ;
this . camera . setArmLocation ( xCenter , yCenter , zCenter ) ;
} ;
} ;
/ * *
/ * *
* Convert a 3 D location to a 2 D location on screen
* Convert a 3 D location to a 2 D location on screen
* http : //en.wikipedia.org/wiki/3D_projection
* @ param { Point3d } point3d A 3 D point with parameters x , y , z
* @ return { Point2d } point2d A 2 D point with parameters x , y
* Source : ttp : //en.wikipedia.org/wiki/3D_projection
*
* @ param { Point3d } point3d A 3 D point with parameters x , y , z
* @ returns { Point2d } point2d A 2 D point with parameters x , y
* /
* /
Graph3d . prototype . _convert3Dto2D = function ( point3d ) {
Graph3d . prototype . _convert3Dto2D = function ( point3d ) {
var translation = this . _convertPointToTranslation ( point3d ) ;
var translation = this . _convertPointToTranslation ( point3d ) ;
@ -196,11 +201,12 @@ Graph3d.prototype._convert3Dto2D = function(point3d) {
/ * *
/ * *
* Convert a 3 D location its translation seen from the camera
* Convert a 3 D location its translation seen from the camera
* http : //en.wikipedia.org/wiki/3D_projection
* @ param { Point3d } point3d A 3 D point with parameters x , y , z
* @ return { Point3d } translation A 3 D point with parameters x , y , z This is
* the translation of the point , seen from the
* camera
* Source : http : //en.wikipedia.org/wiki/3D_projection
*
* @ param { Point3d } point3d A 3 D point with parameters x , y , z
* @ returns { Point3d } translation A 3 D point with parameters x , y , z This is
* the translation of the point , seen from the
* camera .
* /
* /
Graph3d . prototype . _convertPointToTranslation = function ( point3d ) {
Graph3d . prototype . _convertPointToTranslation = function ( point3d ) {
var cameraLocation = this . camera . getCameraLocation ( ) ,
var cameraLocation = this . camera . getCameraLocation ( ) ,
@ -231,10 +237,11 @@ Graph3d.prototype._convertPointToTranslation = function(point3d) {
/ * *
/ * *
* Convert a translation point to a point on the screen
* Convert a translation point to a point on the screen
* @ param { Point3d } translation A 3 D point with parameters x , y , z This is
* the translation of the point , seen from the
* camera
* @ return { Point2d } point2d A 2 D point with parameters x , y
*
* @ param { Point3d } translation A 3 D point with parameters x , y , z This is
* the translation of the point , seen from the
* camera .
* @ returns { Point2d } point2d A 2 D point with parameters x , y
* /
* /
Graph3d . prototype . _convertTranslationToScreen = function ( translation ) {
Graph3d . prototype . _convertTranslationToScreen = function ( translation ) {
var ex = this . eye . x ,
var ex = this . eye . x ,
@ -321,20 +328,21 @@ Graph3d.prototype.getDistinctValues = function(data, column) {
}
}
/ * *
* Get the absolute min / max values for the passed data column .
*
* @ returns { Range } A Range instance with min / max members properly set .
* /
Graph3d . prototype . getColumnRange = function ( data , column ) {
Graph3d . prototype . getColumnRange = function ( data , column ) {
var minMax ;
var range = new Range ( ) ;
// Adjust the range so that it covers all values in the passed data elements.
for ( var i = 0 ; i < data . length ; i ++ ) {
for ( var i = 0 ; i < data . length ; i ++ ) {
var item = data [ i ] [ column ] ;
var item = data [ i ] [ column ] ;
if ( i === 0 ) {
minMax = { min : item , max : item } ;
} else {
if ( minMax . min > item ) { minMax . min = item ; }
if ( minMax . max < item ) { minMax . max = item ; }
}
range . adjust ( item ) ;
}
}
return minMax ;
return range ;
} ;
} ;
@ -363,7 +371,7 @@ Graph3d.prototype._checkValueField = function (data) {
}
}
// The data must also contain this field.
// The data must also contain this field.
// Note that only first data element is checked
// Note that only first data element is checked.
if ( data [ 0 ] [ this . colValue ] === undefined ) {
if ( data [ 0 ] [ this . colValue ] === undefined ) {
throw new Error ( 'Expected data to have '
throw new Error ( 'Expected data to have '
+ ' field \'' + this . colValue + '\' '
+ ' field \'' + this . colValue + '\' '
@ -373,11 +381,37 @@ Graph3d.prototype._checkValueField = function (data) {
} ;
} ;
/ * *
* Set default values for range
*
* The default values override the range values , if defined .
*
* Because it 's possible that only defaultMin or defaultMax is set, it' s better
* to pass in a range already set with the min / max set from the data . Otherwise ,
* it ' s quite hard to process the min / max properly .
* /
Graph3d . prototype . _setRangeDefaults = function ( range , defaultMin , defaultMax ) {
if ( defaultMin !== undefined ) {
range . min = defaultMin ;
}
if ( defaultMax !== undefined ) {
range . max = defaultMax ;
}
// This is the original way that the default min/max values were adjusted.
// TODO: Perhaps it's better if an error is thrown if the values do not agree.
// But this will change the behaviour.
if ( range . max <= range . min ) range . max = range . min + 1 ;
} ;
/ * *
/ * *
* Initialize the data from the data table . Calculate minimum and maximum values
* Initialize the data from the data table . Calculate minimum and maximum values
* and column index values
* and column index values
* @ param { Array | DataSet | DataView } rawData The data containing the items for the Graph .
* @ param { Number } style Style Number
* @ param { Array | DataSet | DataView } rawData The data containing the items for
* the Graph .
* @ param { Number } style Style Number
* /
* /
Graph3d . prototype . _dataInitialize = function ( rawData , style ) {
Graph3d . prototype . _dataInitialize = function ( rawData , style ) {
var me = this ;
var me = this ;
@ -419,17 +453,6 @@ Graph3d.prototype._dataInitialize = function (rawData, style) {
this . colY = 'y' ;
this . colY = 'y' ;
this . colZ = 'z' ;
this . colZ = 'z' ;
// check if a filter column is provided
if ( data [ 0 ] . hasOwnProperty ( 'filter' ) ) {
// Only set this field if it's actually present
this . colFilter = 'filter' ;
if ( this . dataFilter === undefined ) {
this . dataFilter = new Filter ( rawData , this . colFilter , this ) ;
this . dataFilter . setOnLoadCallback ( function ( ) { me . redraw ( ) ; } ) ;
}
}
var withBars = this . style == Graph3d . STYLE . BAR ||
var withBars = this . style == Graph3d . STYLE . BAR ||
this . style == Graph3d . STYLE . BARCOLOR ||
this . style == Graph3d . STYLE . BARCOLOR ||
@ -455,39 +478,49 @@ Graph3d.prototype._dataInitialize = function (rawData, style) {
}
}
// calculate minimums and maximums
// calculate minimums and maximums
var xRange = this . getColumnRange ( data , this . colX ) ;
var NUMSTEPS = 5 ;
var xRange = this . getColumnRange ( data , this . colX ) ;
if ( withBars ) {
if ( withBars ) {
xRange . min -= this . xBarWidth / 2 ;
xRange . max += this . xBarWidth / 2 ;
xRange . expand ( this . xBarWidth / 2 ) ;
}
}
this . xMin = ( this . defaultXMin !== undefined ) ? this . defaultXMin : xRange . min ;
this . xMax = ( this . defaultXMax !== undefined ) ? this . defaultXMax : xRange . max ;
if ( this . xMax <= this . xMin ) this . xMax = this . xMin + 1 ;
this . xStep = ( this . defaultXStep !== undefined ) ? this . defaultXStep : ( this . xMax - this . xMin ) / 5 ;
this . _setRangeDefaults ( xRange , this . defaultXMin , this . defaultXMax ) ;
this . xRange = xRange ;
this . xStep = ( this . defaultXStep !== undefined ) ? this . defaultXStep : xRange . range ( ) / NUMSTEPS ;
var yRange = this . getColumnRange ( data , this . colY ) ;
var yRange = this . getColumnRange ( data , this . colY ) ;
if ( withBars ) {
if ( withBars ) {
yRange . min -= this . yBarWidth / 2 ;
yRange . max += this . yBarWidth / 2 ;
yRange . expand ( this . yBarWidth / 2 ) ;
}
}
this . yMin = ( this . defaultYMin !== undefined ) ? this . defaultYMin : yRange . min ;
this . yMax = ( this . defaultYMax !== undefined ) ? this . defaultYMax : yRange . max ;
if ( this . yMax <= this . yMin ) this . yMax = this . yMin + 1 ;
this . yStep = ( this . defaultYStep !== undefined ) ? this . defaultYStep : ( this . yMax - this . yMin ) / 5 ;
this . _setRangeDefaults ( yRange , this . defaultYMin , this . defaultYMax ) ;
this . yRange = yRange ;
this . yStep = ( this . defaultYStep !== undefined ) ? this . defaultYStep : yRange . range ( ) / NUMSTEPS ;
var zRange = this . getColumnRange ( data , this . colZ ) ;
this . zMin = ( this . defaultZMin !== undefined ) ? this . defaultZMin : zRange . min ;
this . zMax = ( this . defaultZMax !== undefined ) ? this . defaultZMax : zRange . max ;
if ( this . zMax <= this . zMin ) this . zMax = this . zMin + 1 ;
this . zStep = ( this . defaultZStep !== undefined ) ? this . defaultZStep : ( this . zMax - this . zMin ) / 5 ;
var zRange = this . getColumnRange ( data , this . colZ ) ;
this . _setRangeDefaults ( zRange , this . defaultZMin , this . defaultZMax ) ;
this . zRange = zRange ;
this . zStep = ( this . defaultZStep !== undefined ) ? this . defaultZStep : zRange . range ( ) / NUMSTEPS ;
if ( data [ 0 ] . hasOwnProperty ( 'style' ) ) {
if ( data [ 0 ] . hasOwnProperty ( 'style' ) ) {
this . colValue = 'style' ;
this . colValue = 'style' ;
var valueRange = this . getColumnRange ( data , this . colValue ) ;
var valueRange = this . getColumnRange ( data , this . colValue ) ;
this . valueMin = ( this . defaultValueMin !== undefined ) ? this . defaultValueMin : valueRange . min ;
this . valueMax = ( this . defaultValueMax !== undefined ) ? this . defaultValueMax : valueRange . max ;
if ( this . valueMax <= this . valueMin ) this . valueMax = this . valueMin + 1 ;
this . _setRangeDefaults ( valueRange , this . defaultValueMin , this . defaultValueMax ) ;
this . valueRange = valueRange ;
}
// check if a filter column is provided
// Needs to be started after zRange is defined
if ( data [ 0 ] . hasOwnProperty ( 'filter' ) ) {
// Only set this field if it's actually present
this . colFilter = 'filter' ;
if ( this . dataFilter === undefined ) {
this . dataFilter = new Filter ( rawData , this . colFilter , this ) ;
this . dataFilter . setOnLoadCallback ( function ( ) { me . redraw ( ) ; } ) ;
}
}
}
// set the scale dependent on the ranges.
// set the scale dependent on the ranges.
this . _setScale ( ) ;
this . _setScale ( ) ;
@ -497,11 +530,14 @@ Graph3d.prototype._dataInitialize = function (rawData, style) {
/ * *
/ * *
* Filter the data based on the current filter
* Filter the data based on the current filter
* @ param { Array } data
* @ return { Array } dataPoints Array with point objects which can be drawn on screen
*
* @ param { Array } data
* @ returns { Array } dataPoints Array with point objects which can be drawn on
* screen
* /
* /
Graph3d . prototype . _getDataPoints = function ( data ) {
Graph3d . prototype . _getDataPoints = function ( data ) {
// TODO: store the created matrix dataPoints in the filters instead of reloading each time
// TODO: store the created matrix dataPoints in the filters instead of
// reloading each time.
var x , y , i , z , obj , point ;
var x , y , i , z , obj , point ;
var dataPoints = [ ] ;
var dataPoints = [ ] ;
@ -539,7 +575,8 @@ Graph3d.prototype._getDataPoints = function (data) {
y = data [ i ] [ this . colY ] || 0 ;
y = data [ i ] [ this . colY ] || 0 ;
z = data [ i ] [ this . colZ ] || 0 ;
z = data [ i ] [ this . colZ ] || 0 ;
var xIndex = dataX . indexOf ( x ) ; // TODO: implement Array().indexOf() for Internet Explorer
// TODO: implement Array().indexOf() for Internet Explorer
var xIndex = dataX . indexOf ( x ) ;
var yIndex = dataY . indexOf ( y ) ;
var yIndex = dataY . indexOf ( y ) ;
if ( dataMatrix [ xIndex ] === undefined ) {
if ( dataMatrix [ xIndex ] === undefined ) {
@ -556,7 +593,7 @@ Graph3d.prototype._getDataPoints = function (data) {
obj . point = point3d ;
obj . point = point3d ;
obj . trans = undefined ;
obj . trans = undefined ;
obj . screen = undefined ;
obj . screen = undefined ;
obj . bottom = new Point3d ( x , y , this . zM in ) ;
obj . bottom = new Point3d ( x , y , this . zRange . m in ) ;
dataMatrix [ xIndex ] [ yIndex ] = obj ;
dataMatrix [ xIndex ] [ yIndex ] = obj ;
@ -594,7 +631,7 @@ Graph3d.prototype._getDataPoints = function (data) {
obj = { } ;
obj = { } ;
obj . point = point ;
obj . point = point ;
obj . bottom = new Point3d ( point . x , point . y , this . zM in ) ;
obj . bottom = new Point3d ( point . x , point . y , this . zRange . m in ) ;
obj . trans = undefined ;
obj . trans = undefined ;
obj . screen = undefined ;
obj . screen = undefined ;
@ -614,6 +651,7 @@ Graph3d.prototype._getDataPoints = function (data) {
/ * *
/ * *
* Create the main frame for the Graph3d .
* Create the main frame for the Graph3d .
*
* This function is executed once when a Graph3d object is created . The frame
* This function is executed once when a Graph3d object is created . The frame
* contains a canvas , and this canvas contains all objects like the axis and
* contains a canvas , and this canvas contains all objects like the axis and
* nodes .
* nodes .
@ -670,10 +708,11 @@ Graph3d.prototype.create = function () {
/ * *
/ * *
* Set a new size for the graph
* Set a new size for the graph
* @ param { string } width Width in pixels or percentage ( for example '800px'
* or '50%' )
* @ param { string } height Height in pixels or percentage ( for example '400px'
* or '30%' )
*
* @ param { string } width Width in pixels or percentage ( for example '800px'
* or '50%' )
* @ param { string } height Height in pixels or percentage ( for example '400px'
* or '30%' )
* /
* /
Graph3d . prototype . setSize = function ( width , height ) {
Graph3d . prototype . setSize = function ( width , height ) {
this . frame . style . width = width ;
this . frame . style . width = width ;
@ -749,8 +788,9 @@ Graph3d.prototype._resizeCenter = function() {
/ * *
/ * *
* Retrieve the current camera rotation
* Retrieve the current camera rotation
* @ return { object } An object with parameters horizontal , vertical , and
* distance
*
* @ returns { object } An object with parameters horizontal , vertical , and
* distance
* /
* /
Graph3d . prototype . getCameraPosition = function ( ) {
Graph3d . prototype . getCameraPosition = function ( ) {
var pos = this . camera . getArmRotation ( ) ;
var pos = this . camera . getArmRotation ( ) ;
@ -781,6 +821,7 @@ Graph3d.prototype._readData = function(data) {
/ * *
/ * *
* Replace the dataset of the Graph3d
* Replace the dataset of the Graph3d
*
* @ param { Array | DataSet | DataView } data
* @ param { Array | DataSet | DataView } data
* /
* /
Graph3d . prototype . setData = function ( data ) {
Graph3d . prototype . setData = function ( data ) {
@ -795,6 +836,7 @@ Graph3d.prototype.setData = function (data) {
/ * *
/ * *
* Update the options . Options will be merged with current options
* Update the options . Options will be merged with current options
*
* @ param { Object } options
* @ param { Object } options
* /
* /
Graph3d . prototype . setOptions = function ( options ) {
Graph3d . prototype . setOptions = function ( options ) {
@ -1017,8 +1059,8 @@ Graph3d.prototype._redrawLegend = function() {
// print value text along the legend edge
// print value text along the legend edge
var gridLineLen = 5 ; // px
var gridLineLen = 5 ; // px
var legendMin = isValueLegend ? this . valueM in : this . zM in ;
var legendMax = isValueLegend ? this . valueM ax : this . zM ax ;
var legendMin = isValueLegend ? this . valueRange . m in : this . zRange . m in ;
var legendMax = isValueLegend ? this . valueRange . m ax : this . zRange . m ax ;
var step = new StepNumber ( legendMin , legendMax , ( legendMax - legendMin ) / 5 , true ) ;
var step = new StepNumber ( legendMin , legendMax , ( legendMax - legendMin ) / 5 , true ) ;
step . start ( true ) ;
step . start ( true ) ;
@ -1217,8 +1259,7 @@ Graph3d.prototype._redrawAxis = function() {
var ctx = this . _getContext ( ) ,
var ctx = this . _getContext ( ) ,
from , to , step , prettyStep ,
from , to , step , prettyStep ,
text , xText , yText , zText ,
text , xText , yText , zText ,
offset , xOffset , yOffset ,
xMin2d , xMax2d ;
offset , xOffset , yOffset ;
// TODO: get the actual rendered style of the containerElement
// TODO: get the actual rendered style of the containerElement
//ctx.font = this.containerElement.style.font;
//ctx.font = this.containerElement.style.font;
@ -1231,32 +1272,36 @@ Graph3d.prototype._redrawAxis = function() {
var armAngle = this . camera . getArmRotation ( ) . horizontal ;
var armAngle = this . camera . getArmRotation ( ) . horizontal ;
var armVector = new Point2d ( Math . cos ( armAngle ) , Math . sin ( armAngle ) ) ;
var armVector = new Point2d ( Math . cos ( armAngle ) , Math . sin ( armAngle ) ) ;
var xRange = this . xRange ;
var yRange = this . yRange ;
var zRange = this . zRange ;
// draw x-grid lines
// draw x-grid lines
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
prettyStep = ( this . defaultXStep === undefined ) ;
prettyStep = ( this . defaultXStep === undefined ) ;
step = new StepNumber ( this . xMin , this . xMax , this . xStep , prettyStep ) ;
step = new StepNumber ( xRange . min , xRange . m ax, this . xStep , prettyStep ) ;
step . start ( true ) ;
step . start ( true ) ;
while ( ! step . end ( ) ) {
while ( ! step . end ( ) ) {
var x = step . getCurrent ( ) ;
var x = step . getCurrent ( ) ;
if ( this . showGrid ) {
if ( this . showGrid ) {
from = new Point3d ( x , this . yMin , this . zM in) ;
to = new Point3d ( x , this . yMax , this . zM in) ;
from = new Point3d ( x , yRange . min , zRange . m in) ;
to = new Point3d ( x , yRange . max , zRange . m in) ;
this . _line3d ( ctx , from , to , this . gridColor ) ;
this . _line3d ( ctx , from , to , this . gridColor ) ;
}
}
else {
else {
from = new Point3d ( x , this . yMin , this . zM in) ;
to = new Point3d ( x , this . yM in+ gridLenX , this . zM in) ;
from = new Point3d ( x , yRange . min , zRange . m in) ;
to = new Point3d ( x , yRange . m in+ gridLenX , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
from = new Point3d ( x , this . yMax , this . zM in) ;
to = new Point3d ( x , this . yM ax- gridLenX , this . zM in) ;
from = new Point3d ( x , yRange . max , zRange . m in) ;
to = new Point3d ( x , yRange . m ax- gridLenX , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
}
}
yText = ( armVector . x > 0 ) ? this . yMin : this . yM ax;
var point3d = new Point3d ( x , yText , this . zM in) ;
yText = ( armVector . x > 0 ) ? yRange . min : yRange . m ax;
var point3d = new Point3d ( x , yText , zRange . m in) ;
var msg = ' ' + this . xValueLabel ( x ) + ' ' ;
var msg = ' ' + this . xValueLabel ( x ) + ' ' ;
this . drawAxisLabelX ( ctx , point3d , msg , armAngle , textMargin ) ;
this . drawAxisLabelX ( ctx , point3d , msg , armAngle , textMargin ) ;
@ -1266,29 +1311,29 @@ Graph3d.prototype._redrawAxis = function() {
// draw y-grid lines
// draw y-grid lines
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
prettyStep = ( this . defaultYStep === undefined ) ;
prettyStep = ( this . defaultYStep === undefined ) ;
step = new StepNumber ( this . yMin , this . yM ax, this . yStep , prettyStep ) ;
step = new StepNumber ( yRange . min , yRange . m ax, this . yStep , prettyStep ) ;
step . start ( true ) ;
step . start ( true ) ;
while ( ! step . end ( ) ) {
while ( ! step . end ( ) ) {
var y = step . getCurrent ( ) ;
var y = step . getCurrent ( ) ;
if ( this . showGrid ) {
if ( this . showGrid ) {
from = new Point3d ( this . xMin , y , this . zM in) ;
to = new Point3d ( this . xMax , y , this . zM in) ;
from = new Point3d ( xRange . min , y , zRange . m in) ;
to = new Point3d ( xRange . max , y , zRange . m in) ;
this . _line3d ( ctx , from , to , this . gridColor ) ;
this . _line3d ( ctx , from , to , this . gridColor ) ;
}
}
else {
else {
from = new Point3d ( this . xMin , y , this . zM in) ;
to = new Point3d ( this . xM in+ gridLenY , y , this . zM in) ;
from = new Point3d ( xRange . min , y , zRange . m in) ;
to = new Point3d ( xRange . m in+ gridLenY , y , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
from = new Point3d ( this . xMax , y , this . zM in) ;
to = new Point3d ( this . xM ax- gridLenY , y , this . zM in) ;
from = new Point3d ( xRange . max , y , zRange . m in) ;
to = new Point3d ( xRange . m ax- gridLenY , y , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
}
}
xText = ( armVector . y > 0 ) ? this . xMin : this . xM ax;
point3d = new Point3d ( xText , y , this . zM in) ;
xText = ( armVector . y > 0 ) ? xRange . min : xRange . m ax;
point3d = new Point3d ( xText , y , zRange . m in) ;
var msg = ' ' + this . yValueLabel ( y ) + ' ' ;
var msg = ' ' + this . yValueLabel ( y ) + ' ' ;
this . drawAxisLabelY ( ctx , point3d , msg , armAngle , textMargin ) ;
this . drawAxisLabelY ( ctx , point3d , msg , armAngle , textMargin ) ;
@ -1298,11 +1343,11 @@ Graph3d.prototype._redrawAxis = function() {
// draw z-grid lines and axis
// draw z-grid lines and axis
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
prettyStep = ( this . defaultZStep === undefined ) ;
prettyStep = ( this . defaultZStep === undefined ) ;
step = new StepNumber ( this . zMin , this . zM ax, this . zStep , prettyStep ) ;
step = new StepNumber ( zRange . min , zRange . m ax, this . zStep , prettyStep ) ;
step . start ( true ) ;
step . start ( true ) ;
xText = ( armVector . x > 0 ) ? this . xMin : this . xM ax;
yText = ( armVector . y < 0 ) ? this . yMin : this . yM ax;
xText = ( armVector . x > 0 ) ? xRange . min : xRange . m ax;
yText = ( armVector . y < 0 ) ? yRange . min : yRange . m ax;
while ( ! step . end ( ) ) {
while ( ! step . end ( ) ) {
var z = step . getCurrent ( ) ;
var z = step . getCurrent ( ) ;
@ -1320,39 +1365,42 @@ Graph3d.prototype._redrawAxis = function() {
}
}
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
from = new Point3d ( xText , yText , this . zM in) ;
to = new Point3d ( xText , yText , this . zM ax) ;
from = new Point3d ( xText , yText , zRange . m in) ;
to = new Point3d ( xText , yText , zRange . m ax) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
// draw x-axis
// draw x-axis
var xMin2d ;
var xMax2d ;
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
// line at yMin
// line at yMin
xMin2d = new Point3d ( this . xMin , this . yMin , this . zM in) ;
xMax2d = new Point3d ( this . xMax , this . yMin , this . zM in) ;
xMin2d = new Point3d ( xRange . min , yRange . min , zRange . m in) ;
xMax2d = new Point3d ( xRange . max , yRange . min , zRange . m in) ;
this . _line3d ( ctx , xMin2d , xMax2d , this . axisColor ) ;
this . _line3d ( ctx , xMin2d , xMax2d , this . axisColor ) ;
// line at ymax
// line at ymax
xMin2d = new Point3d ( this . xMin , this . yMax , this . zM in) ;
xMax2d = new Point3d ( this . xMax , this . yMax , this . zM in) ;
xMin2d = new Point3d ( xRange . min , yRange . max , zRange . m in) ;
xMax2d = new Point3d ( xRange . max , yRange . max , zRange . m in) ;
this . _line3d ( ctx , xMin2d , xMax2d , this . axisColor ) ;
this . _line3d ( ctx , xMin2d , xMax2d , this . axisColor ) ;
// draw y-axis
// draw y-axis
ctx . lineWidth = 1 ;
ctx . lineWidth = 1 ;
// line at xMin
// line at xMin
from = new Point3d ( this . xMin , this . yMin , this . zM in) ;
to = new Point3d ( this . xMin , this . yMax , this . zM in) ;
from = new Point3d ( xRange . min , yRange . min , zRange . m in) ;
to = new Point3d ( xRange . min , yRange . max , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
// line at xMax
// line at xMax
from = new Point3d ( this . xMax , this . yMin , this . zM in) ;
to = new Point3d ( this . xMax , this . yMax , this . zM in) ;
from = new Point3d ( xRange . max , yRange . min , zRange . m in) ;
to = new Point3d ( xRange . max , yRange . max , zRange . m in) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
this . _line3d ( ctx , from , to , this . axisColor ) ;
// draw x-label
// draw x-label
var xLabel = this . xLabel ;
var xLabel = this . xLabel ;
if ( xLabel . length > 0 ) {
if ( xLabel . length > 0 ) {
yOffset = 0.1 / this . scale . y ;
yOffset = 0.1 / this . scale . y ;
xText = ( this . xMin + this . xMax ) / 2 ;
yText = ( armVector . x > 0 ) ? this . yM in - yOffset : this . yM ax + yOffset ;
text = new Point3d ( xText , yText , this . zM in) ;
xText = xRange . center ( ) / 2 ;
yText = ( armVector . x > 0 ) ? yRange . m in - yOffset : yRange . m ax + yOffset ;
text = new Point3d ( xText , yText , zRange . m in) ;
this . drawAxisLabelX ( ctx , text , xLabel , armAngle ) ;
this . drawAxisLabelX ( ctx , text , xLabel , armAngle ) ;
}
}
@ -1360,9 +1408,9 @@ Graph3d.prototype._redrawAxis = function() {
var yLabel = this . yLabel ;
var yLabel = this . yLabel ;
if ( yLabel . length > 0 ) {
if ( yLabel . length > 0 ) {
xOffset = 0.1 / this . scale . x ;
xOffset = 0.1 / this . scale . x ;
xText = ( armVector . y > 0 ) ? this . xM in - xOffset : this . xM ax + xOffset ;
yText = ( this . yMin + this . yMax ) / 2 ;
text = new Point3d ( xText , yText , this . zM in) ;
xText = ( armVector . y > 0 ) ? xRange . m in - xOffset : xRange . m ax + xOffset ;
yText = yRange . center ( ) / 2 ;
text = new Point3d ( xText , yText , zRange . m in) ;
this . drawAxisLabelY ( ctx , text , yLabel , armAngle ) ;
this . drawAxisLabelY ( ctx , text , yLabel , armAngle ) ;
}
}
@ -1371,9 +1419,9 @@ Graph3d.prototype._redrawAxis = function() {
var zLabel = this . zLabel ;
var zLabel = this . zLabel ;
if ( zLabel . length > 0 ) {
if ( zLabel . length > 0 ) {
offset = 30 ; // pixels. // TODO: relate to the max width of the values on the z axis?
offset = 30 ; // pixels. // TODO: relate to the max width of the values on the z axis?
xText = ( armVector . x > 0 ) ? this . xMin : this . xM ax;
yText = ( armVector . y < 0 ) ? this . yMin : this . yM ax;
zText = ( this . zMin + this . zMax ) / 2 ;
xText = ( armVector . x > 0 ) ? xRange . min : xRange . m ax;
yText = ( armVector . y < 0 ) ? yRange . min : yRange . m ax;
zText = zRange . center ( ) / 2 ;
text = new Point3d ( xText , yText , zText ) ;
text = new Point3d ( xText , yText , zText ) ;
this . drawAxisLabelZ ( ctx , text , zLabel , offset ) ;
this . drawAxisLabelZ ( ctx , text , zLabel , offset ) ;
@ -1436,6 +1484,7 @@ Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borde
// calculate all corner points
// calculate all corner points
var me = this ;
var me = this ;
var point3d = point . point ;
var point3d = point . point ;
var zMin = this . zRange . min ;
var top = [
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 ) } ,
@ -1443,10 +1492,10 @@ Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borde
{ point : new Point3d ( point3d . x - xWidth , point3d . y + yWidth , point3d . z ) }
{ point : new Point3d ( point3d . x - xWidth , point3d . y + yWidth , point3d . z ) }
] ;
] ;
var bottom = [
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 ) }
{ point : new Point3d ( point3d . x - xWidth , point3d . y - yWidth , zMin ) } ,
{ point : new Point3d ( point3d . x + xWidth , point3d . y - yWidth , zMin ) } ,
{ point : new Point3d ( point3d . x + xWidth , point3d . y + yWidth , zMin ) } ,
{ point : new Point3d ( point3d . x - xWidth , point3d . y + yWidth , zMin ) }
] ;
] ;
// calculate screen location of the points
// calculate screen location of the points
@ -1555,7 +1604,7 @@ Graph3d.prototype._drawCircle = function(ctx, point, color, borderColor, size) {
* /
* /
Graph3d . prototype . _getColorsRegular = function ( point ) {
Graph3d . prototype . _getColorsRegular = function ( point ) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var hue = ( 1 - ( point . point . z - this . zM in ) * this . scale . z / this . verticalRatio ) * 240 ;
var hue = ( 1 - ( point . point . z - this . zRange . m in ) * this . scale . z / this . verticalRatio ) * 240 ;
var color = this . _hsv2rgb ( hue , 1 , 1 ) ;
var color = this . _hsv2rgb ( hue , 1 , 1 ) ;
var borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
var borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
@ -1572,7 +1621,7 @@ Graph3d.prototype._getColorsRegular = function(point) {
* /
* /
Graph3d . prototype . _getColorsColor = function ( point ) {
Graph3d . prototype . _getColorsColor = function ( point ) {
// calculate the color based on the value
// calculate the color based on the value
var hue = ( 1 - ( point . point . value - this . valueM in ) * this . scale . value ) * 240 ;
var hue = ( 1 - ( point . point . value - this . valueRange . m in ) * this . scale . value ) * 240 ;
var color = this . _hsv2rgb ( hue , 1 , 1 ) ;
var color = this . _hsv2rgb ( hue , 1 , 1 ) ;
var borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
var borderColor = this . _hsv2rgb ( hue , 1 , 0.8 ) ;
@ -1656,7 +1705,7 @@ Graph3d.prototype._redrawBarColorGraphPoint = function(ctx, point) {
* /
* /
Graph3d . prototype . _redrawBarSizeGraphPoint = function ( ctx , point ) {
Graph3d . prototype . _redrawBarSizeGraphPoint = function ( ctx , point ) {
// calculate size for the bar
// calculate size for the bar
var fraction = ( point . point . value - this . valueMin ) / ( this . valueMax - this . valueMin ) ;
var fraction = ( point . point . value - this . valueRange . min ) / this . valueRange . range ( ) ;
var xWidth = ( this . xBarWidth / 2 ) * ( fraction * 0.8 + 0.2 ) ;
var xWidth = ( this . xBarWidth / 2 ) * ( fraction * 0.8 + 0.2 ) ;
var yWidth = ( this . yBarWidth / 2 ) * ( fraction * 0.8 + 0.2 ) ;
var yWidth = ( this . yBarWidth / 2 ) * ( fraction * 0.8 + 0.2 ) ;
@ -1704,7 +1753,7 @@ Graph3d.prototype._redrawDotColorGraphPoint = function(ctx, point) {
* /
* /
Graph3d . prototype . _redrawDotSizeGraphPoint = function ( ctx , point ) {
Graph3d . prototype . _redrawDotSizeGraphPoint = function ( ctx , point ) {
var dotSize = this . _dotSize ( ) ;
var dotSize = this . _dotSize ( ) ;
var fraction = ( point . point . value - this . valueMin ) / ( this . valueMax - this . valueMin ) ;
var fraction = ( point . point . value - this . valueRange . min ) / this . valueRange . range ( ) ;
var size = dotSize / 2 + 2 * dotSize * fraction ;
var size = dotSize / 2 + 2 * dotSize * fraction ;
var colors = this . _getColorsSize ( ) ;
var colors = this . _getColorsSize ( ) ;
@ -1747,7 +1796,7 @@ Graph3d.prototype._redrawSurfaceGraphPoint = function(ctx, point) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var zAvg = ( point . point . z + right . point . z + top . point . z + cross . point . z ) / 4 ;
var zAvg = ( point . point . z + right . point . z + top . point . z + cross . point . z ) / 4 ;
var h = ( 1 - ( zAvg - this . zM in ) * this . scale . z / this . verticalRatio ) * 240 ;
var h = ( 1 - ( zAvg - this . zRange . m in ) * this . scale . z / this . verticalRatio ) * 240 ;
var s = 1 ; // saturation
var s = 1 ; // saturation
var v ;
var v ;
@ -1785,7 +1834,7 @@ Graph3d.prototype._drawGridLine = function(ctx, from, to) {
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
// calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
var zAvg = ( from . point . z + to . point . z ) / 2 ;
var zAvg = ( from . point . z + to . point . z ) / 2 ;
var h = ( 1 - ( zAvg - this . zM in ) * this . scale . z / this . verticalRatio ) * 240 ;
var h = ( 1 - ( zAvg - this . zRange . m in ) * this . scale . z / this . verticalRatio ) * 240 ;
ctx . lineWidth = this . _getStrokeWidth ( from ) * 2 ;
ctx . lineWidth = this . _getStrokeWidth ( from ) * 2 ;
ctx . strokeStyle = this . _hsv2rgb ( h , 1 , 1 ) ;
ctx . strokeStyle = this . _hsv2rgb ( h , 1 , 1 ) ;
@ -2076,9 +2125,11 @@ Graph3d.prototype._onWheel = function(event) {
/ * *
/ * *
* Test whether a point lies inside given 2 D triangle
* Test whether a point lies inside given 2 D triangle
* @ param { Point2d } point
* @ param { Point2d [ ] } triangle
* @ return { boolean } Returns true if given point lies inside or on the edge of the triangle
*
* @ param { Point2d } point
* @ param { Point2d [ ] } triangle
* @ returns { boolean } true if given point lies inside or on the edge of the
* triangle , false otherwise
* @ private
* @ private
* /
* /
Graph3d . prototype . _insideTriangle = function ( point , triangle ) {
Graph3d . prototype . _insideTriangle = function ( point , triangle ) {
@ -2102,9 +2153,11 @@ Graph3d.prototype._insideTriangle = function (point, triangle) {
/ * *
/ * *
* Find a data point close to given screen position ( x , y )
* Find a data point close to given screen position ( x , y )
* @ param { Number } x
* @ param { Number } y
* @ return { Object | null } The closest data point or null if not close to any data point
*
* @ param { Number } x
* @ param { Number } y
* @ returns { Object | null } The closest data point or null if not close to any
* data point
* @ private
* @ private
* /
* /
Graph3d . prototype . _dataPointFromXY = function ( x , y ) {
Graph3d . prototype . _dataPointFromXY = function ( x , y ) {
@ -2268,8 +2321,9 @@ Graph3d.prototype._hideTooltip = function () {
/ * *
/ * *
* Get the horizontal mouse position from a mouse event
* Get the horizontal mouse position from a mouse event
* @ param { Event } event
* @ return { Number } mouse x
*
* @ param { Event } event
* @ returns { Number } mouse x
* /
* /
function getMouseX ( event ) {
function getMouseX ( event ) {
if ( 'clientX' in event ) return event . clientX ;
if ( 'clientX' in event ) return event . clientX ;
@ -2278,8 +2332,9 @@ function getMouseX (event) {
/ * *
/ * *
* Get the vertical mouse position from a mouse event
* Get the vertical mouse position from a mouse event
* @ param { Event } event
* @ return { Number } mouse y
*
* @ param { Event } event
* @ returns { Number } mouse y
* /
* /
function getMouseY ( event ) {
function getMouseY ( event ) {
if ( 'clientY' in event ) return event . clientY ;
if ( 'clientY' in event ) return event . clientY ;
@ -2293,19 +2348,16 @@ function getMouseY (event) {
/ * *
/ * *
* Set the rotation and distance of the camera
* Set the rotation and distance of the camera
* @ param { Object } pos An object with the camera position . The object
* contains three parameters :
* - horizontal { Number }
* The horizontal rotation , between 0 and 2 * PI .
* Optional , can be left undefined .
* - vertical { Number }
* The vertical rotation , between 0 and 0.5 * PI
* if vertical = 0.5 * PI , the graph is shown from the
* top . Optional , can be left undefined .
* - distance { Number }
* The ( normalized ) distance of the camera to the
* center of the graph , a value between 0.71 and 5.0 .
* Optional , can be left undefined .
*
* @ param { Object } pos An object with the camera position
* @ param { ? Number } pos . horizontal The horizontal rotation , between 0 and 2 * PI .
* Optional , can be left undefined .
* @ param { ? Number } pos . vertical The vertical rotation , between 0 and 0.5 * PI .
* if vertical = 0.5 * PI , the graph is shown from
* the top . Optional , can be left undefined .
* @ param { ? Number } pos . distance The ( normalized ) distance of the camera to the
* center of the graph , a value between 0.71 and
* 5.0 . Optional , can be left undefined .
* /
* /
Graph3d . prototype . setCameraPosition = function ( pos ) {
Graph3d . prototype . setCameraPosition = function ( pos ) {
Settings . setCameraPosition ( pos , this ) ;
Settings . setCameraPosition ( pos , this ) ;