'use strict'; /** * Licensed Materials - Property of IBM * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2016, 2017 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['../../lib/@waca/core-client/js/core-client/ui/core/Class'], function (Class) { var ScaleUtil = {}; /** * Functions used to handle calculation of scale options for infographic display functionality * */ ScaleUtil = Class.extend({ // Constants that handles conversion between numeric and text values. Used for readability, as numbers are used for scale slider min/max but they interpret as text values SCALE_VALUE_FEW: 0, SCALE_VALUE_DEFAULT: 1, SCALE_VALUE_MANY: 2, PERCENT_OPTIMAL_VALUE: 0.1, PERCENT_SCALE_OPTIONS: [0.01, 0.1, 1], /** * Calculates the default scale value for a given input number * @param rawNum - Input number to be infographically displayed * @param isPercent - If the raw number is used to represent a percentage infographic * @returns The default scale value to be used */ calcOptimalValue: function calcOptimalValue(rawNum, isPercent) { // If rawNum is null (i.e. no value provided, treat same as zero case to avoid returning errors later on if (rawNum === null) { rawNum = 0; } // Null if not a number if (typeof rawNum !== 'number') { return null; } if (isPercent) { return this.PERCENT_OPTIMAL_VALUE; } // Take abs to handle negative numbers var absNum = Math.abs(rawNum); var sign = this.getSign(rawNum) || 1; var numLen = Math.ceil(Math.log(absNum + 1) / Math.LN10); // Default optimal value is 1. var optimalValue = 1; // If the number of digits is greater than 2 than calculate the optimal value if (numLen > 2) { optimalValue = Math.pow(10, numLen - 2); } return optimalValue * sign; }, /** * Gets an object containing a list of scale options as well as the default for a given number * @param rawNum - Input number to be infographically displayed * @param isPercent - If the raw number is used to represent a percentage infographic * @returns An object containing an array of scaling options to be used, as well as the default scale to be shown */ getScalingProperties: function getScalingProperties(rawNum, isPercent) { // If rawNum is null (i.e. no value provided, treat same as zero case to avoid returning errors later on if (rawNum === null) { rawNum = 0; } // Null if not a number if (typeof rawNum !== 'number') { return null; } if (isPercent) { return { availableScales: this.PERCENT_SCALE_OPTIONS, optimalScale: this.PERCENT_OPTIMAL_VALUE, scalingOptions: [this.SCALE_VALUE_FEW, this.SCALE_VALUE_DEFAULT, this.SCALE_VALUE_MANY] }; } // get the absolute number var absNum = Math.abs(rawNum); // get the sign of the number to help handle negative numbers var sign = this.getSign(rawNum) || 1; // Get the ideal scale for the given number var optimalValue = this.calcOptimalValue(absNum); var availableScales = [optimalValue * sign]; // Only add lower scale option if the default is greater than one if (optimalValue > 1) { availableScales.unshift(optimalValue / 10 * sign); } // Check if potential high value is valid scale option for input number var potentialHigh = optimalValue * 10; if (absNum / potentialHigh >= 1) { availableScales.push(potentialHigh * sign); } // Assemble both parts of final product to be returned to user var result = { availableScales: availableScales, optimalScale: optimalValue * sign }; result.scalingOptions = this._getScaleOptions(result, isPercent); return result; }, /** * Returns the corresponding min/max values for slider which user utilizes to select preferred scale option * @param {Number} rawNum - Raw input number which is being used to determine the scale * @param isPercent - If the raw number is used to represent a percentage infographic * @returns result object containing min and max value for slider */ getMinMax: function getMinMax(rawNum, isPercent) { // If rawNum is null (i.e. no value provided, treat same as zero case to avoid returning errors later on if (rawNum === null) { rawNum = 0; } var scales = this.getScalingProperties(rawNum, isPercent); return { min: scales.scalingOptions[0], max: scales.scalingOptions[scales.scalingOptions.length - 1] }; }, /** * Given a corresponding value and scale to use, calculate the number of shapes and partial shapes to return to the user * @param value - The value we are calculating the number off of * @param scale - The scale that will be used * @param isPercent - If the raw number is used to represent a percentage infographic * @returns An object that contains the number of shapes and partial shapes to be displayed in the infographic summary */ getScaleComponents: function getScaleComponents(value, scale, isPercent) { // If rawNum is null (i.e. no value provided, treat same as zero case to avoid returning errors later on if (value === null) { value = 0; } /** * Used to divide a number by a floating point decimal, which can sometimes lead to repeating decimal values using the normal '/' operator * @param numerator - Numerator of division expression * @param denominator - Denominator of division expression * @returns Result of numerator divided by denominator */ function _division(numerator, denominator) { while (denominator < 1 && denominator > 0) { denominator *= 10; numerator *= 10; } return numerator / denominator; } /** * Used to find the remainder of a number by a floating point decimal, which can sometimes lead to repeating decimal values using the normal '%' operator * @param numerator - Numerator of remainder expression * @param denominator - Denominator of remainder expression * @returns remainder of expression */ function _remainder(numerator, denominator) { return numerator - denominator * Math.floor(_division(numerator, denominator)); } value = Math.abs(value); scale = Math.abs(scale); var numShapes = Math.floor(_division(value, scale)); var partialValue = _division(_remainder(value, scale), scale); partialValue = parseFloat(partialValue.toFixed(2)); var numGreyedShapes; if (isPercent) { numGreyedShapes = _division(1, scale) - numShapes - Math.ceil(partialValue); } else { numGreyedShapes = 0; } return { numShapes: numShapes, partialValue: partialValue, numGreyedShapes: numGreyedShapes }; }, _getScaleOptions: function _getScaleOptions(scaleData) { var numOfScales = scaleData.availableScales.length; var result; if (numOfScales === 3) { result = [this.SCALE_VALUE_FEW, this.SCALE_VALUE_DEFAULT, this.SCALE_VALUE_MANY]; } else if (numOfScales === 1) { result = [this.SCALE_VALUE_DEFAULT]; } else if (scaleData.availableScales.indexOf(scaleData.optimalScale) === 0) { result = [this.SCALE_VALUE_FEW, this.SCALE_VALUE_DEFAULT]; } else if (scaleData.availableScales.indexOf(scaleData.optimalScale) === 1) { result = [this.SCALE_VALUE_DEFAULT, this.SCALE_VALUE_MANY]; } return result; }, getSign: function getSign(x) { x = +x; // convert to a number if (isNaN(x)) { return NaN; } return x >= 0 ? 1 : -1; } }); return new ScaleUtil(); }); //# sourceMappingURL=ScaleUtil.js.map