diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 76d5aaa0..19bc59ef 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -39,12 +39,83 @@ var OPTIONKEYS = [ 'animationPreload', 'animationAutoStart', 'axisColor', - 'gridColor' + 'gridColor', + 'xCenter', + 'yCenter' ]; /** - * Copy fields from src to dst in a controlled manner. + * Default values for certain option fields. + * + * 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'. + */ +var DEFAULTS = { + width : '400px', + height : '400px', + filterLabel : 'time', + legendLabel : 'value', + xLabel : 'x', + yLabel : 'y', + zLabel : 'z', + xValueLabel : function(v) { return v; }, + yValueLabel : function(v) { return v; }, + zValueLabel : function(v) { return v; }, + showGrid : true, + showPerspective : true, + showShadow : false, + keepAspectRatio : true, + verticalRatio : 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube' + animationInterval: 1000, // milliseconds + animationPreload : false, + axisColor : '#4D4D4D', + gridColor : '#D3D3D3', + xCenter : '55%', + yCenter : '50%' + + + // Following not in defaults (yet) but present in user settings + // These will be initialized as 'undefined' + //'showAnimationControls', + //'animationAutoStart' +}; + + + +/** + * 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 + */ +function forceCopy(src, dst, fields) { + for (var i in fields) { + var field = fields[i]; + dst[field] = src[field]; + } +} + + +/** + * 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. @@ -85,45 +156,38 @@ function Graph3d(container, data, options) { // create variables and set default values this.containerElement = container; - this.width = '400px'; - this.height = '400px'; + + this.dataTable = null; // The original data table + this.dataPoints = null; // The table with point objects + + + // + // Start Settings + // + + // Handle the defaults which can be simply copied over + forceCopy(DEFAULTS, this, OPTIONKEYS); + + // Following are internal fields, not part of the user settings this.margin = 10; // px - this.defaultXCenter = '55%'; - this.defaultYCenter = '50%'; + 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.xLabel = 'x'; - this.yLabel = 'y'; - this.zLabel = 'z'; + // The rest of the fields. + // These require special attention in some way + // TODO: handle these - var passValueFn = function(v) { return v; }; - this.xValueLabel = passValueFn; - this.yValueLabel = passValueFn; - this.zValueLabel = passValueFn; - - this.filterLabel = 'time'; - this.legendLabel = 'value'; this.showLegend = undefined; // auto by default (based on graph style) this.style = Graph3d.STYLE.DOT; - this.showPerspective = true; - this.showGrid = true; - this.keepAspectRatio = true; - this.showShadow = false; - this.showGrayBottom = false; // TODO: this does not work correctly - this.showTooltip = false; - this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube' - this.animationInterval = 1000; // milliseconds - 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 - this.dataPoints = null; // The table with point objects - // the column indexes this.colX = undefined; this.colY = undefined; @@ -147,15 +211,16 @@ function Graph3d(container, data, options) { // TODO: customize axis range // colors - this.axisColor = '#4D4D4D'; - this.gridColor = '#D3D3D3'; this.dataColor = { fill: '#7DC1FF', stroke: '#3267D2', strokeWidth: 1 // px }; - this.dotSizeRatio = 0.02; // size of the dots as a fraction of the graph width + + // + // End Settings + // // create a frame and canvas this.create(); @@ -281,8 +346,8 @@ Graph3d.prototype._convertTranslationToScreen = function(translation) { // shift and scale the point to the center of the screen // use the width of the graph to scale both horizontally and vertically. return new Point2d( - this.xcenter + bx * this.frame.canvas.clientWidth, - this.ycenter - by * this.frame.canvas.clientWidth); + this.currentXCenter + bx * this.frame.canvas.clientWidth, + this.currentYCenter - by * this.frame.canvas.clientWidth); }; @@ -809,30 +874,30 @@ Graph3d.prototype.animationStop = function() { /** - * Resize the center position based on the current values in this.defaultXCenter - * and this.defaultYCenter (which are strings with a percentage or a value - * in pixels). The center positions are the variables this.xCenter - * and this.yCenter + * Resize the center position based on the current values in this.xCenter + * and this.yCenter (which are strings with a percentage or a value + * in pixels). The center positions are the variables this.currentXCenter + * and this.currentYCenter */ Graph3d.prototype._resizeCenter = function() { // calculate the horizontal center position - if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') { - this.xcenter = - parseFloat(this.defaultXCenter) / 100 * + if (this.xCenter.charAt(this.xCenter.length-1) === '%') { + this.currentXCenter = + parseFloat(this.xCenter) / 100 * this.frame.canvas.clientWidth; } else { - this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px + this.currentXCenter = parseFloat(this.xCenter); // supposed to be in px } // calculate the vertical center position - if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') { - this.ycenter = - parseFloat(this.defaultYCenter) / 100 * + if (this.yCenter.charAt(this.yCenter.length-1) === '%') { + this.currentYCenter = + parseFloat(this.yCenter) / 100 * (this.frame.canvas.clientHeight - this.frame.filter.clientHeight); } else { - this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px + this.currentYCenter = parseFloat(this.yCenter); // supposed to be in px } }; @@ -931,8 +996,6 @@ Graph3d.prototype.setOptions = function (options) { safeCopy(options, this, OPTIONKEYS); // Handle the rest of the parameters - if (options.xCenter !== undefined) this.defaultXCenter = options.xCenter; - if (options.yCenter !== undefined) this.defaultYCenter = options.yCenter; if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; if (options.style !== undefined) {