|
|
@ -7,21 +7,11 @@ var Camera = require('./Camera'); |
|
|
|
var Filter = require('./Filter'); |
|
|
|
var Slider = require('./Slider'); |
|
|
|
var StepNumber = require('./StepNumber'); |
|
|
|
var Settings = require('./Settings'); |
|
|
|
|
|
|
|
|
|
|
|
/// 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 |
|
|
|
}; |
|
|
|
Graph3d.STYLE = Settings.STYLE; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
@ -135,7 +125,7 @@ function Graph3d(container, data, options) { |
|
|
|
// create a frame and canvas
|
|
|
|
this.create(); |
|
|
|
|
|
|
|
this._setDefaults(); |
|
|
|
Settings.setDefaults(this); |
|
|
|
|
|
|
|
// the column indexes
|
|
|
|
this.colX = undefined; |
|
|
@ -302,32 +292,6 @@ Graph3d.prototype._calcTranslations = function(points, sort) { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Retrieve the style index from given styleName |
|
|
|
* @param {string} styleName Style name such as 'dot', 'grid', 'dot-line' |
|
|
|
* @return {Number} styleNumber Enumeration value representing the style, or -1 |
|
|
|
* when not found |
|
|
|
*/ |
|
|
|
Graph3d.prototype._getStyleNumber = function(styleName) { |
|
|
|
switch (styleName) { |
|
|
|
case 'dot': return Graph3d.STYLE.DOT; |
|
|
|
case 'dot-line': return Graph3d.STYLE.DOTLINE; |
|
|
|
case 'dot-color': return Graph3d.STYLE.DOTCOLOR; |
|
|
|
case 'dot-size': return Graph3d.STYLE.DOTSIZE; |
|
|
|
case 'line': return Graph3d.STYLE.LINE; |
|
|
|
case 'grid': return Graph3d.STYLE.GRID; |
|
|
|
case 'surface': return Graph3d.STYLE.SURFACE; |
|
|
|
case 'bar': return Graph3d.STYLE.BAR; |
|
|
|
case 'bar-color': return Graph3d.STYLE.BARCOLOR; |
|
|
|
case 'bar-size': return Graph3d.STYLE.BARSIZE; |
|
|
|
} |
|
|
|
|
|
|
|
return -1; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Determine the indexes of the data columns, based on the given style and data |
|
|
|
* @param {DataSet} data |
|
|
@ -855,7 +819,7 @@ Graph3d.prototype.setOptions = function (options) { |
|
|
|
|
|
|
|
this.animationStop(); |
|
|
|
|
|
|
|
this._setOptions(options); |
|
|
|
Settings.setOptions(options, this); |
|
|
|
|
|
|
|
this.setSize(this.width, this.height); |
|
|
|
|
|
|
@ -2216,335 +2180,9 @@ function getMouseY (event) { |
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Methods for handling settings
|
|
|
|
// Public methods for specific settings
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Field names in the options hash which are of relevance to the user. |
|
|
|
* |
|
|
|
* Specifically, these are the fields which require no special handling, |
|
|
|
* and can be directly copied over. |
|
|
|
*/ |
|
|
|
var OPTIONKEYS = [ |
|
|
|
'width', |
|
|
|
'height', |
|
|
|
'filterLabel', |
|
|
|
'legendLabel', |
|
|
|
'xLabel', |
|
|
|
'yLabel', |
|
|
|
'zLabel', |
|
|
|
'xValueLabel', |
|
|
|
'yValueLabel', |
|
|
|
'zValueLabel', |
|
|
|
'showGrid', |
|
|
|
'showPerspective', |
|
|
|
'showShadow', |
|
|
|
'keepAspectRatio', |
|
|
|
'verticalRatio', |
|
|
|
'showAnimationControls', |
|
|
|
'animationInterval', |
|
|
|
'animationPreload', |
|
|
|
'animationAutoStart', |
|
|
|
'axisColor', |
|
|
|
'gridColor', |
|
|
|
'xCenter', |
|
|
|
'yCenter' |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Field names in the options hash which are of relevance to the user. |
|
|
|
* |
|
|
|
* Same as OPTIONKEYS, but internally these fields are stored with |
|
|
|
* prefix 'default' in the name. |
|
|
|
*/ |
|
|
|
var PREFIXEDOPTIONKEYS = [ |
|
|
|
'xBarWidth', |
|
|
|
'yBarWidth', |
|
|
|
'valueMin', |
|
|
|
'valueMax', |
|
|
|
'xMin', |
|
|
|
'xMax', |
|
|
|
'xStep', |
|
|
|
'yMin', |
|
|
|
'yMax', |
|
|
|
'yStep', |
|
|
|
'zMin', |
|
|
|
'zMax', |
|
|
|
'zStep' |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Make first letter of parameter upper case. |
|
|
|
* |
|
|
|
* Source: http://stackoverflow.com/a/1026087
|
|
|
|
*/ |
|
|
|
function capitalize(str) { |
|
|
|
if (str === undefined || str === "") { |
|
|
|
return str; |
|
|
|
} |
|
|
|
|
|
|
|
return str.charAt(0).toUpperCase() + str.slice(1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Add a prefix to a field name, taking style guide into account |
|
|
|
*/ |
|
|
|
function prefixFieldName(prefix, fieldName) { |
|
|
|
if (prefix === undefined || prefix === "") { |
|
|
|
return fieldName; |
|
|
|
} |
|
|
|
|
|
|
|
return prefix + capitalize(fieldName); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Forcibly copy fields from src to dst in a controlled manner. |
|
|
|
* |
|
|
|
* A given field in dst will always be overwitten. If this field |
|
|
|
* is undefined or not present in src, the field in dst will |
|
|
|
* be explicitly set to undefined. |
|
|
|
* |
|
|
|
* The intention here is to be able to reset all option fields. |
|
|
|
* |
|
|
|
* Only the fields mentioned in array 'fields' will be handled. |
|
|
|
* |
|
|
|
* @param fields array with names of fields to copy |
|
|
|
* @param prefix optional; prefix to use for the target fields. |
|
|
|
*/ |
|
|
|
function forceCopy(src, dst, fields, prefix) { |
|
|
|
var srcKey; |
|
|
|
var dstKey; |
|
|
|
|
|
|
|
for (var i in fields) { |
|
|
|
srcKey = fields[i]; |
|
|
|
dstKey = prefixFieldName(prefix, srcKey); |
|
|
|
|
|
|
|
dst[dstKey] = src[srcKey]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Copy fields from src to dst in a safe and controlled manner. |
|
|
|
* |
|
|
|
* Only the fields mentioned in array 'fields' will be copied over, |
|
|
|
* and only if these are actually defined. |
|
|
|
* |
|
|
|
* @param fields array with names of fields to copy |
|
|
|
* @param prefix optional; prefix to use for the target fields. |
|
|
|
*/ |
|
|
|
function safeCopy(src, dst, fields, prefix) { |
|
|
|
var srcKey; |
|
|
|
var dstKey; |
|
|
|
|
|
|
|
for (var i in fields) { |
|
|
|
srcKey = fields[i]; |
|
|
|
if (src[srcKey] === undefined) continue; |
|
|
|
|
|
|
|
dstKey = prefixFieldName(prefix, srcKey); |
|
|
|
|
|
|
|
dst[dstKey] = src[srcKey]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Graph3d.prototype._setDefaults = function() { |
|
|
|
|
|
|
|
// Handle the defaults which can be simply copied over
|
|
|
|
forceCopy(DEFAULTS, this, OPTIONKEYS); |
|
|
|
forceCopy(DEFAULTS, this, PREFIXEDOPTIONKEYS, 'default'); |
|
|
|
|
|
|
|
// Handle the more complex ('special') fields
|
|
|
|
this._setSpecialSettings(DEFAULTS, this); |
|
|
|
|
|
|
|
// Following are internal fields, not part of the user settings
|
|
|
|
this.margin = 10; // px
|
|
|
|
this.showGrayBottom = false; // TODO: this does not work correctly
|
|
|
|
this.showTooltip = false; |
|
|
|
this.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width
|
|
|
|
this.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window?
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Graph3d.prototype._setOptions = function(options) { |
|
|
|
if (options === undefined) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Handle the parameters which can be simply copied over
|
|
|
|
safeCopy(options, this, OPTIONKEYS); |
|
|
|
safeCopy(options, this, PREFIXEDOPTIONKEYS, 'default'); |
|
|
|
|
|
|
|
// Handle the more complex ('special') fields
|
|
|
|
this._setSpecialSettings(options, this); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Special handling for certain parameters |
|
|
|
* |
|
|
|
* 'Special' here means: setting requires more than a simple copy |
|
|
|
*/ |
|
|
|
Graph3d.prototype._setSpecialSettings = function(src, dst) { |
|
|
|
if (src.backgroundColor !== undefined) { |
|
|
|
this._setBackgroundColor(src.backgroundColor, dst); |
|
|
|
} |
|
|
|
|
|
|
|
this._setDataColor(src.dataColor, dst); |
|
|
|
this._setStyle(src.style, dst); |
|
|
|
this._setShowLegend(src.showLegend, dst); |
|
|
|
this._setCameraPosition(src.cameraPosition, dst); |
|
|
|
|
|
|
|
// As special fields go, this is an easy one; just a translation of the name.
|
|
|
|
// Can't use this.tooltip directly, because that field exists internally
|
|
|
|
if (src.tooltip !== undefined) { |
|
|
|
dst.showTooltip = src.tooltip; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Set the value of setting 'showLegend' |
|
|
|
* |
|
|
|
* This depends on the value of the style fields, so it must be called |
|
|
|
* after the style field has been initialized. |
|
|
|
*/ |
|
|
|
Graph3d.prototype._setShowLegend = function(showLegend, dst) { |
|
|
|
if (showLegend === undefined) { |
|
|
|
// If the default was auto, make a choice for this field
|
|
|
|
var isAutoByDefault = (DEFAULTS.showLegend === undefined); |
|
|
|
|
|
|
|
if (isAutoByDefault) { |
|
|
|
// these styles default to having legends
|
|
|
|
var isLegendGraphStyle = this.style === Graph3d.STYLE.DOTCOLOR |
|
|
|
|| this.style === Graph3d.STYLE.DOTSIZE; |
|
|
|
|
|
|
|
this.showLegend = isLegendGraphStyle; |
|
|
|
} else { |
|
|
|
// Leave current value as is
|
|
|
|
} |
|
|
|
} else { |
|
|
|
dst.showLegend = showLegend; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
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 Graph3d.STYLE) { |
|
|
|
if (Graph3d.STYLE[n] === style) { |
|
|
|
valid = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!valid) { |
|
|
|
throw new Error('Style \'' + style + '\' is invalid'); |
|
|
|
} |
|
|
|
|
|
|
|
styleNumber = style; |
|
|
|
} |
|
|
|
|
|
|
|
dst.style = styleNumber; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Set the background styling for the graph |
|
|
|
* @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor |
|
|
|
*/ |
|
|
|
Graph3d.prototype._setBackgroundColor = function(backgroundColor, dst) { |
|
|
|
var fill = 'white'; |
|
|
|
var stroke = 'gray'; |
|
|
|
var strokeWidth = 1; |
|
|
|
|
|
|
|
if (typeof(backgroundColor) === 'string') { |
|
|
|
fill = backgroundColor; |
|
|
|
stroke = 'none'; |
|
|
|
strokeWidth = 0; |
|
|
|
} |
|
|
|
else if (typeof(backgroundColor) === 'object') { |
|
|
|
if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; |
|
|
|
if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; |
|
|
|
if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; |
|
|
|
} |
|
|
|
else { |
|
|
|
throw new Error('Unsupported type of backgroundColor'); |
|
|
|
} |
|
|
|
|
|
|
|
dst.frame.style.backgroundColor = fill; |
|
|
|
dst.frame.style.borderColor = stroke; |
|
|
|
dst.frame.style.borderWidth = strokeWidth + 'px'; |
|
|
|
dst.frame.style.borderStyle = 'solid'; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Graph3d.prototype._setDataColor = function(dataColor, dst) { |
|
|
|
if (dataColor === undefined) { |
|
|
|
return; // Nothing to do
|
|
|
|
} |
|
|
|
|
|
|
|
if (dst.dataColor === undefined) { |
|
|
|
dst.dataColor = {}; |
|
|
|
} |
|
|
|
|
|
|
|
if (typeof dataColor === 'string') { |
|
|
|
dst.dataColor.fill = dataColor; |
|
|
|
dst.dataColor.stroke = dataColor; |
|
|
|
} |
|
|
|
else { |
|
|
|
if (dataColor.fill) { |
|
|
|
dst.dataColor.fill = dataColor.fill; |
|
|
|
} |
|
|
|
if (dataColor.stroke) { |
|
|
|
dst.dataColor.stroke = dataColor.stroke; |
|
|
|
} |
|
|
|
if (dataColor.strokeWidth !== undefined) { |
|
|
|
dst.dataColor.strokeWidth = dataColor.strokeWidth; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Graph3d.prototype._setCameraPosition = function(cameraPosition, dst) { |
|
|
|
var camPos = cameraPosition; |
|
|
|
if (camPos === undefined) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (dst.camera === undefined) { |
|
|
|
dst.camera = new Camera(); |
|
|
|
} |
|
|
|
|
|
|
|
dst.camera.setArmRotation(camPos.horizontal, camPos.vertical); |
|
|
|
dst.camera.setArmLength(camPos.distance); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Public methods for specific settings
|
|
|
|
//
|
|
|
|
|
|
|
|
/** |
|
|
|
* Set the rotation and distance of the camera |
|
|
|
* @param {Object} pos An object with the camera position. The object |
|
|
@ -2562,13 +2200,13 @@ Graph3d.prototype._setCameraPosition = function(cameraPosition, dst) { |
|
|
|
* Optional, can be left undefined. |
|
|
|
*/ |
|
|
|
Graph3d.prototype.setCameraPosition = function(pos) { |
|
|
|
this._setCameraPosition(pos, this); |
|
|
|
Settings.setCameraPosition(pos, this); |
|
|
|
this.redraw(); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// End methods for handling settings
|
|
|
|
// End public methods for specific settings
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|