Browse Source

Merge pull request #2199 from wimrijnders/PR14

Final cleanup for settings handling
codeClimate
yotamberk 8 years ago
committed by GitHub
parent
commit
503099328f
2 changed files with 503 additions and 427 deletions
  1. +65
    -427
      lib/graph3d/Graph3d.js
  2. +438
    -0
      lib/graph3d/Settings.js

+ 65
- 427
lib/graph3d/Graph3d.js View File

@ -7,80 +7,22 @@ var Camera = require('./Camera');
var Filter = require('./Filter');
var Slider = require('./Slider');
var StepNumber = require('./StepNumber');
var Settings = require('./Settings');
// -----------------------------------------------------------------------------
// Definitions private to module
// -----------------------------------------------------------------------------
/// 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;
/**
* 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.
* 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.
*/
var PREFIXEDOPTIONKEYS = [
'xBarWidth',
'yBarWidth',
'valueMin',
'valueMax',
'xMin',
'xMax',
'xStep',
'yMin',
'yMax',
'yStep',
'zMin',
'zMax',
'zStep'
];
var autoByDefault = undefined;
/**
@ -89,15 +31,8 @@ var PREFIXEDOPTIONKEYS = [
* 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 'undefined' can
* be assumed. Of course, it does no harm to set a field explicitly to
* 'undefined' here.
*
* A value of 'undefined' here normally means:
*
* 'derive from current data and graph style'
*
* In the code, this is indicated by the comment 'auto by default'.
* If a field is not in this list, a default value of 'autoByDefault'
* is assumed, which is just an alias for 'undefined'.
*/
var DEFAULTS = {
width : '400px',
@ -114,29 +49,27 @@ var DEFAULTS = {
showPerspective : true,
showShadow : false,
keepAspectRatio : true,
verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube'
verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube'
showAnimationControls: undefined, // auto by default
animationInterval : 1000, // milliseconds
showAnimationControls: autoByDefault,
animationInterval : 1000, // milliseconds
animationPreload : false,
animationAutoStart : undefined, // auto by default
animationAutoStart : autoByDefault,
axisColor : '#4D4D4D',
gridColor : '#D3D3D3',
xCenter : '55%',
yCenter : '50%',
// Following require special handling, therefore not mentioned in the OPTIONKEYS tables.
style : Graph3d.STYLE.DOT,
tooltip : false,
showLegend : undefined, // auto by default (based on graph style)
backgroundColor : undefined,
showLegend : autoByDefault, // determined by graph style
backgroundColor : autoByDefault,
dataColor : {
fill : '#7DC1FF',
stroke : '#3267D2',
strokeWidth: 1 // px
strokeWidth: 1 // px
},
cameraPosition : {
@ -145,103 +78,22 @@ var DEFAULTS = {
distance : 1.7
},
// Following stored internally with field prefix 'default'
// All these are 'auto by default'
xBarWidth : undefined,
yBarWidth : undefined,
valueMin : undefined,
valueMax : undefined,
xMin : undefined,
xMax : undefined,
xStep : undefined,
yMin : undefined,
yMax : undefined,
yStep : undefined,
zMin : undefined,
zMax : undefined,
zStep : undefined
xBarWidth : autoByDefault,
yBarWidth : autoByDefault,
valueMin : autoByDefault,
valueMax : autoByDefault,
xMin : autoByDefault,
xMax : autoByDefault,
xStep : autoByDefault,
yMin : autoByDefault,
yMax : autoByDefault,
yStep : autoByDefault,
zMin : autoByDefault,
zMax : autoByDefault,
zStep : autoByDefault
};
/**
* 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];
}
}
// -----------------------------------------------------------------------------
// Class Graph3d
// -----------------------------------------------------------------------------
@ -272,27 +124,7 @@ function Graph3d(container, data, options) {
// create a frame and canvas
this.create();
//
// Set Defaults
//
// Handle the defaults which can be simply copied over
forceCopy(DEFAULTS, this, OPTIONKEYS);
forceCopy(DEFAULTS, this, PREFIXEDOPTIONKEYS, 'default');
// 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?
// Handle the more complex ('special') fields
this._setSpecialSettings(DEFAULTS, this);
//
// End Set Defaults
//
Settings.setDefaults(DEFAULTS, this);
// the column indexes
this.colX = undefined;
@ -459,223 +291,6 @@ Graph3d.prototype._calcTranslations = function(points, sort) {
};
// -----------------------------------------------------------------------------
// Methods for handling settings
// -----------------------------------------------------------------------------
/**
* 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
* 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.
*/
Graph3d.prototype.setCameraPosition = function(pos) {
this._setCameraPosition(pos, this);
this.redraw();
};
// -----------------------------------------------------------------------------
// End methods for handling settings
// -----------------------------------------------------------------------------
/**
* 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
@ -1210,16 +825,7 @@ Graph3d.prototype.setOptions = function (options) {
this.animationStop();
if (options !== undefined) {
// retrieve parameter values
// 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);
}
Settings.setOptions(options, this);
this.setSize(this.width, this.height);
@ -2575,4 +2181,36 @@ function getMouseY (event) {
return event.targetTouches[0] && event.targetTouches[0].clientY || 0;
}
// -----------------------------------------------------------------------------
// Public methods for specific settings
// -----------------------------------------------------------------------------
/**
* 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.
*/
Graph3d.prototype.setCameraPosition = function(pos) {
Settings.setCameraPosition(pos, this);
this.redraw();
};
// -----------------------------------------------------------------------------
// End public methods for specific settings
// -----------------------------------------------------------------------------
module.exports = Graph3d;

+ 438
- 0
lib/graph3d/Settings.js View File

@ -0,0 +1,438 @@
////////////////////////////////////////////////////////////////////////////////
// This modules handles the options for Graph3d.
//
////////////////////////////////////////////////////////////////////////////////
var Camera = require('./Camera');
var Point3d = require('./Point3d');
// 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
};
// The string representations of the styles
var STYLENAME = {
'dot' : STYLE.DOT,
'dot-line' : STYLE.DOTLINE,
'dot-color': STYLE.DOTCOLOR,
'dot-size' : STYLE.DOTSIZE,
'line' : STYLE.LINE,
'grid' : STYLE.GRID,
'surface' : STYLE.SURFACE,
'bar' : STYLE.BAR,
'bar-color': STYLE.BARCOLOR,
'bar-size' : STYLE.BARSIZE
};
/**
* 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'
];
// Placeholder for DEFAULTS reference
var DEFAULTS = undefined;
/**
* Check if given hash is empty.
*
* Source: http://stackoverflow.com/a/679937
*/
function isEmpty(obj) {
for(var prop in obj) {
if (obj.hasOwnProperty(prop))
return false;
}
return true;
}
/**
* 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];
}
}
/**
* Initialize dst with the values in src.
*
* src is the hash with the default values.
* A reference DEFAULTS to this hash is stored locally for
* further handling.
*
* For now, dst is assumed to be a Graph3d instance.
*/
function setDefaults(src, dst) {
if (src === undefined || isEmpty(src)) {
throw new Error('No DEFAULTS passed');
}
if (dst === undefined) {
throw new Error('No dst passed');
}
// Remember defaults for future reference
DEFAULTS = src;
// Handle the defaults which can be simply copied over
forceCopy(src, dst, OPTIONKEYS);
forceCopy(src, dst, PREFIXEDOPTIONKEYS, 'default');
// Handle the more complex ('special') fields
setSpecialSettings(src, dst);
// Following are internal fields, not part of the user settings
dst.margin = 10; // px
dst.showGrayBottom = false; // TODO: this does not work correctly
dst.showTooltip = false;
dst.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width
dst.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window?
}
function setOptions(options, dst) {
if (options === undefined) {
return;
}
if (dst === undefined) {
throw new Error('No dst passed');
}
if (DEFAULTS === undefined || isEmpty(DEFAULTS)) {
throw new Error('DEFAULTS not set for module Settings');
}
// Handle the parameters which can be simply copied over
safeCopy(options, dst, OPTIONKEYS);
safeCopy(options, dst, PREFIXEDOPTIONKEYS, 'default');
// Handle the more complex ('special') fields
setSpecialSettings(options, dst);
}
/**
* Special handling for certain parameters
*
* 'Special' here means: setting requires more than a simple copy
*/
function setSpecialSettings(src, dst) {
if (src.backgroundColor !== undefined) {
setBackgroundColor(src.backgroundColor, dst);
}
setDataColor(src.dataColor, dst);
setStyle(src.style, dst);
setShowLegend(src.showLegend, dst);
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.
*/
function setShowLegend(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 = dst.style === STYLE.DOTCOLOR
|| dst.style === STYLE.DOTSIZE;
dst.showLegend = isLegendGraphStyle;
} else {
// Leave current value as is
}
} else {
dst.showLegend = showLegend;
}
}
/**
* 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
*/
function getStyleNumberByName(styleName) {
var number = STYLENAME[styleName];
if (number === undefined) {
return -1;
}
return number;
}
/**
* Check if given number is a valid style number.
*
* @return true if valid, false otherwise
*/
function checkStyleNumber(style) {
var valid = false;
for (var n in STYLE) {
if (STYLE[n] === style) {
valid = true;
break;
}
}
return valid;
}
function setStyle(style, dst) {
if (style === undefined) {
return; // Nothing to do
}
var styleNumber;
if (typeof style === 'string') {
styleNumber = getStyleNumberByName(style);
if (styleNumber === -1 ) {
throw new Error('Style \'' + style + '\' is invalid');
}
} else {
// Do a pedantic check on style number value
if (!checkStyleNumber(style)) {
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
*/
function setBackgroundColor(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';
}
function setDataColor(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;
}
}
}
function setCameraPosition(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);
}
module.exports.STYLE = STYLE;
module.exports.setDefaults = setDefaults;
module.exports.setOptions = setOptions;
module.exports.setCameraPosition = setCameraPosition;

Loading…
Cancel
Save