Move calculating the min and max of an array to a utility function.
The function can take optional bounds to override the calculated values,
and can take the smaller spanning range of the specified bounds and the
calculated bounds.
MODIFY
src/contourFeature.js
src/contourFeature.js
@@ -24,7 +24,8 @@ var meshFeature = require('./meshFeature');
*/
/**
- * Contour specification.
+ * Contour specification. All of these properties can be functions, which get
+ * passed the `geo.meshFeature.meshInfo` object.
*
* @typedef {geo.meshFeature.meshSpec} geo.contourFeature.contourSpec
* @property {number} [min] Minimum contour value. If unspecified, taken from
@@ -56,14 +57,7 @@ var meshFeature = require('./meshFeature');
/**
* Computed contour information.
*
- * @typedef {object} geo.contourFeature.contourInfo
- * @property {number[]} elements An array of 0-based indices into the values
- * array. Each set of the three values forms a triangle that should be
- * rendered. If no contour data can be used, this will be a zero-length
- * array and other properties may not be set.
- * @property {number[]} pos An flat array of coordinates for the vertices in
- * the triangular mesh. The array is in the order x0, y0, z0, x1, y1, z1,
- * x2, ..., and is always three times as long as the number of vertices.
+ * @typedef {geo.meshFeature.meshInfo} geo.contourFeature.contourInfo
* @property {number[]} value An array of values that have been normalized to a
* range of [0, steps]. There is one value per vertex.
* @property {number[]} opacity An array of opacities per vertex.
@@ -123,10 +117,7 @@ var contourFeature = function (arg) {
this._createContours = function () {
var contour = m_this.contour,
valueFunc = m_this.style.get('value'),
- stepped = contour.get('stepped')(),
- opacityRange = contour.get('opacityRange')(),
- rangeValues = contour.get('rangeValues')(),
- minValue, maxValue, val, range, i, k;
+ minmax, val, range, i, k;
var result = this._createMesh({
used: function (d, i) {
return util.isNonNullFinite(valueFunc(d, i));
@@ -137,34 +128,25 @@ var contourFeature = function (arg) {
if (!result.numVertices || !result.numElements) {
return result;
}
+ var stepped = contour.get('stepped')(result),
+ opacityRange = contour.get('opacityRange')(result),
+ rangeValues = contour.get('rangeValues')(result);
result.stepped = stepped === undefined || stepped ? true : false;
/* Create the min/max colors and the color array */
result.colorMap = [];
- result.minColor = $.extend({a: contour.get('minOpacity')() || 0},
- util.convertColor(contour.get('minColor')()));
- result.maxColor = $.extend({a: contour.get('maxOpacity')() || 0},
- util.convertColor(contour.get('maxColor')()));
- contour.get('colorRange')().forEach(function (clr, idx) {
+ result.minColor = $.extend({a: contour.get('minOpacity')(result) || 0},
+ util.convertColor(contour.get('minColor')(result)));
+ result.maxColor = $.extend({a: contour.get('maxOpacity')(result) || 0},
+ util.convertColor(contour.get('maxColor')(result)));
+ contour.get('colorRange')(result).forEach(function (clr, idx) {
result.colorMap.push($.extend({
a: opacityRange && opacityRange[idx] !== undefined ? opacityRange[idx] : 1
}, util.convertColor(clr)));
});
/* Get min and max values */
- result.minValue = contour.get('min')();
- result.maxValue = contour.get('max')();
- if (!$.isNumeric(result.minValue) || !$.isNumeric(result.maxValue)) {
- minValue = maxValue = result.value[0];
- for (i = 1; i < result.numVertices; i += 1) {
- minValue = Math.min(minValue, result.value[i]);
- maxValue = Math.max(maxValue, result.value[i]);
- }
- if (!$.isNumeric(result.minValue)) {
- result.minValue = minValue;
- }
- if (!$.isNumeric(result.maxValue)) {
- result.maxValue = maxValue;
- }
- }
+ minmax = util.getMinMaxValues(result.value, contour.get('min')(result), contour.get('max')(result));
+ result.minValue = minmax.min;
+ result.maxValue = minmax.max;
if (!rangeValues || rangeValues.length !== result.colorMap.length + 1) {
rangeValues = null;
}

MODIFY
src/util/index.js
src/util/index.js
@@ -984,6 +984,42 @@ var util = module.exports = {
return leftSide.slice(0, leftSide.length - 1).concat(rightSide);
},
+ /**
+ * Given an array, return the minimum and maximum values within the array.
+ * If a numeric value is specified for one or the other, return that instead.
+ *
+ * @param {number[]} values An array of numeric values.
+ * @param {number} [min] If specified, use this instead of calculating the
+ * minimum.
+ * @param {number} [max] If specified, use this instead of calculating the
+ * maximum.
+ * @param {boolean} [limit=false] If truthy, if `min` is specified, the
+ * returned `min` will be the larger of the specified value and the
+ * computed value, and if `max` is specified, the returned value will
+ * be the smaller of the specified value and the computed value.
+ * @returns {object} An object with `min` and `max`, both numbers. If the
+ * array is empty, `undefined` may be returned for the `min` and `max`.
+ */
+ getMinMaxValues: function (values, min, max, limit) {
+ if (values.length && (limit || !$.isNumeric(min) || !$.isNumeric(max))) {
+ var minValue = values[0],
+ maxValue = values[0],
+ value, i;
+ for (i = values.length - 1; i > 0; i -= 1) {
+ value = values[i];
+ if (value < minValue) { minValue = value; }
+ if (value > maxValue) { maxValue = value; }
+ }
+ if (!$.isNumeric(min) || (limit && minValue > min)) {
+ min = minValue;
+ }
+ if (!$.isNumeric(max) || (limit && maxValue < max)) {
+ max = maxValue;
+ }
+ }
+ return {min: min, max: max};
+ },
+
/**
* Escape any character in a string that has a code point >= 127.
*

MODIFY
tests/cases/util.js
tests/cases/util.js
@@ -111,4 +111,17 @@ describe('geo.util', function () {
{x: 50, y: 10}, {x: 10, y: 5}, {x: 30, y: 3}, {x: 50, y: 5}
]);
});
+
+ it('getMinMaxValues', function () {
+ var values = [
+ 211, 213, 215, 216, 218, 220, 223, 225, 227, 226, 224, 226, 234, 240,
+ 243, 245, 245, 237, 227, 234, 254, 253, 265, 271, 271, 265, 258, 258,
+ 263, 267, 282, 292, 299, 303, 302, 294, 287, 287, 295, 302, 283, 240,
+ 206, 190, 181, 185, 189, 190, 191, 195];
+ expect(util.getMinMaxValues(values)).toEqual({min: 181, max: 303});
+ expect(util.getMinMaxValues(values, 200, 300)).toEqual({min: 200, max: 300});
+ expect(util.getMinMaxValues(values, 100, 400)).toEqual({min: 100, max: 400});
+ expect(util.getMinMaxValues(values, 200, 300, true)).toEqual({min: 200, max: 300});
+ expect(util.getMinMaxValues(values, 100, 400, true)).toEqual({min: 181, max: 303});
+ });
});

Move calculating the min and max of an array to a utility function.

The function can take optional bounds to override the calculated values,
and can take the smaller spanning range of the specified bounds and the
calculated bounds.