Browse Source

Added step to defaults; fixes to detect and survive inconstent data

codeClimate
Wim Rijnders 8 years ago
parent
commit
9a028a8634
2 changed files with 119 additions and 37 deletions
  1. +98
    -37
      lib/graph3d/Graph3d.js
  2. +21
    -0
      lib/graph3d/StepNumber.js

+ 98
- 37
lib/graph3d/Graph3d.js View File

@ -12,6 +12,21 @@ var StepNumber = require('./StepNumber');
// Definitions private to module // Definitions private to module
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/// enumerate the available styles
var STYLE = {
BAR : 0,
BARCOLOR: 1,
BARSIZE : 2,
DOT : 3,
DOTLINE : 4,
DOTCOLOR: 5,
DOTSIZE : 6,
GRID : 7,
LINE : 8,
SURFACE : 9
};
/** /**
* Field names in the options hash which are of relevance to the user. * Field names in the options hash which are of relevance to the user.
* *
@ -32,9 +47,9 @@ var OPTIONKEYS = [
'showGrid', 'showGrid',
'showPerspective', 'showPerspective',
'showShadow', 'showShadow',
'showAnimationControls',
'keepAspectRatio', 'keepAspectRatio',
'verticalRatio', 'verticalRatio',
'showAnimationControls',
'animationInterval', 'animationInterval',
'animationPreload', 'animationPreload',
'animationAutoStart', 'animationAutoStart',
@ -76,28 +91,28 @@ 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'
animationInterval: 1000, // milliseconds
animationPreload : false,
verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube'
showAnimationControls: undefined, // auto by default
animationInterval : 1000, // milliseconds
animationPreload : false,
animationAutoStart : undefined, // auto by default
axisColor : '#4D4D4D', axisColor : '#4D4D4D',
gridColor : '#D3D3D3', gridColor : '#D3D3D3',
xCenter : '55%', xCenter : '55%',
yCenter : '50%', yCenter : '50%',
// Following not in defaults (yet) but present in user settings
// These will be initialized as 'undefined'
//'showAnimationControls',
//'animationAutoStart'
// Following not in OPTIONKEYS because they require special handling, // Following not in OPTIONKEYS because they require special handling,
style : STYLE.DOT, // Can't use Graph3d.STYLE here, not defined yet
backgroundColor : undefined, backgroundColor : undefined,
dataColor : { dataColor : {
fill : '#7DC1FF', fill : '#7DC1FF',
stroke : '#3267D2', stroke : '#3267D2',
strokeWidth: 1 // px
strokeWidth: 1 // px
}, },
cameraPosition : { cameraPosition : {
@ -154,6 +169,15 @@ function safeCopy(src, dst, fields) {
// Class Graph3d // Class Graph3d
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/**
* Enumerate the available styles.
*
* This definition retained for external compatibility
* (It should be internal, but you never know)
*/
Graph3d.STYLE = STYLE;
/** /**
* @constructor Graph3d * @constructor Graph3d
* Graph3d displays data in 3d. * Graph3d displays data in 3d.
@ -201,8 +225,6 @@ function Graph3d(container, data, options) {
this.showLegend = undefined; // auto by default (based on graph style) this.showLegend = undefined; // auto by default (based on graph style)
this.style = Graph3d.STYLE.DOT;
this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window? this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window?
// the column indexes // the column indexes
@ -403,10 +425,10 @@ Graph3d.prototype._setSpecialSettings = function(src, dst) {
} }
this._setDataColor(src.dataColor, dst); this._setDataColor(src.dataColor, dst);
this._setStyle(src.style, dst);
this._setCameraPosition(src.cameraPosition, dst); this._setCameraPosition(src.cameraPosition, dst);
/* TODO /* TODO
setStyle(src.style, dst);
if (src.tooltip !== undefined) { if (src.tooltip !== undefined) {
dst.showTooltip = src.tooltip; dst.showTooltip = src.tooltip;
@ -416,6 +438,39 @@ End TODO */
} }
Graph3d.prototype._setStyle = function(style, dst) {
if (style === undefined) {
return; // Nothing to do
}
var styleNumber;
if (typeof style === 'string') {
styleNumber = this._getStyleNumber(style);
if (styleNumber === -1 ) {
throw new Error('Style \'' + style + '\' is invalid');
}
} else {
// Do a pedantic check on style number value
var valid = false;
for (var n in STYLE) {
if (STYLE[n] === style) {
valid = true;
break;
}
}
if (!valid) {
throw new Error('Style \'' + style + '\' is invalid');
}
styleNumber = style;
}
dst.style = styleNumber;
}
/** /**
@ -521,19 +576,7 @@ Graph3d.prototype.setCameraPosition = function(pos) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/// enumerate the available styles
Graph3d.STYLE = {
BAR: 0,
BARCOLOR: 1,
BARSIZE: 2,
DOT : 3,
DOTLINE : 4,
DOTCOLOR: 5,
DOTSIZE: 6,
GRID : 7,
LINE: 8,
SURFACE : 9
};
/** /**
* Retrieve the style index from given styleName * Retrieve the style index from given styleName
@ -686,13 +729,11 @@ Graph3d.prototype._dataInitialize = function (rawData, style) {
this.colX = 'x'; this.colX = 'x';
this.colY = 'y'; this.colY = 'y';
this.colZ = 'z'; this.colZ = 'z';
this.colValue = 'style';
this.colFilter = 'filter';
// check if a filter column is provided // check if a filter column is provided
if (data[0].hasOwnProperty('filter')) { if (data[0].hasOwnProperty('filter')) {
this.colFilter = 'filter'; // Bugfix: only set this field if it's actually present!
if (this.dataFilter === undefined) { if (this.dataFilter === undefined) {
this.dataFilter = new Filter(rawData, this.colFilter, this); this.dataFilter = new Filter(rawData, this.colFilter, this);
this.dataFilter.setOnLoadCallback(function() {me.redraw();}); this.dataFilter.setOnLoadCallback(function() {me.redraw();});
@ -750,7 +791,9 @@ Graph3d.prototype._dataInitialize = function (rawData, style) {
if (this.zMax <= this.zMin) this.zMax = this.zMin + 1; if (this.zMax <= this.zMin) this.zMax = this.zMin + 1;
this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5; this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5;
if (this.colValue !== undefined) {
// Bugfix: Only handle field 'style' if it's actually present
if (data[0].hasOwnProperty('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.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min;
this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max;
@ -850,6 +893,30 @@ Graph3d.prototype._getDataPoints = function (data) {
} }
} }
else { // 'dot', 'dot-line', etc. else { // 'dot', 'dot-line', etc.
// Bugfix: ensure value field is present in data if expected
var hasValueField = this.style === Graph3d.STYLE.BARCOLOR
|| this.style === Graph3d.STYLE.BARSIZE
|| this.style === Graph3d.STYLE.DOTCOLOR
|| this.style === Graph3d.STYLE.DOTSIZE;
if (hasValueField) {
if (this.colValue === undefined) {
throw new Error('Expected data to have '
+ ' field \'style\' '
+ ' for graph style \'' + this.style + '\''
);
}
if (data[0][this.colValue] === undefined) {
throw new Error('Expected data to have '
+ ' field \'' + this.colValue + '\' '
+ ' for graph style \'' + this.style + '\''
);
}
}
// copy all values from the google data table to a list with Point3d objects // copy all values from the google data table to a list with Point3d objects
for (i = 0; i < data.length; i++) { for (i = 0; i < data.length; i++) {
point = new Point3d(); point = new Point3d();
@ -1077,12 +1144,6 @@ Graph3d.prototype.setOptions = function (options) {
// Handle the rest of the parameters // Handle the rest of the parameters
if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend;
if (options.style !== undefined) {
var styleNumber = this._getStyleNumber(options.style);
if (styleNumber !== -1) {
this.style = styleNumber;
}
}
if (options.tooltip !== undefined) this.showTooltip = options.tooltip; if (options.tooltip !== undefined) this.showTooltip = options.tooltip;
if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth; if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth;

+ 21
- 0
lib/graph3d/StepNumber.js View File

@ -35,6 +35,17 @@ function StepNumber(start, end, step, prettyStep) {
this.setRange(start, end, step, prettyStep); this.setRange(start, end, step, prettyStep);
}; };
/**
* Check for input values, to prevent disasters from happening
*
* Source: http://stackoverflow.com/a/1830844
*/
StepNumber.prototype.isNumeric = function(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
/** /**
* Set a new range: start, end and step. * Set a new range: start, end and step.
* *
@ -45,6 +56,16 @@ function StepNumber(start, end, step, prettyStep) {
* To a pretty step size (like 1, 2, 5, 10, 20, 50, ...) * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/ */
StepNumber.prototype.setRange = function(start, end, step, prettyStep) { StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
if (!this.isNumeric(start)) {
throw new Error('Parameter \'start\' is not numeric; value: ' + start);
}
if (!this.isNumeric(end)) {
throw new Error('Parameter \'end\' is not numeric; value: ' + start);
}
if (!this.isNumeric(step)) {
throw new Error('Parameter \'step\' is not numeric; value: ' + start);
}
this._start = start ? start : 0; this._start = start ? start : 0;
this._end = end ? end : 0; this._end = end ? end : 0;

Loading…
Cancel
Save