util/mesh.js

  1. /**
  2. * Computed colored mesh information.
  3. *
  4. * @typedef {geo.meshFeature.meshInfo} geo.meshFeature.meshColoredInfo
  5. * @extends geo.meshFeature.meshInfo
  6. * @property {number[]} value An array of values that have been normalized to a
  7. * range of [0, steps]. There is one value per vertex or element.
  8. * @property {number[]} opacity An array of opacities per vertex or element.
  9. * @property {number} minValue the minimum value used for the contour. If
  10. * `rangeValues` was specified, this is the first entry of that array.
  11. * @property {number} maxValue the maximum value used for the contour. If
  12. * `rangeValues` was specified, this is the last entry of that array.
  13. * @property {number} factor If linear value scaling is used, this is the
  14. * number of color values divided by the difference between the maximum and
  15. * minimum values. It is ignored if non-linear value scaling is used.
  16. * @property {geo.geoColorObject} minColor The color used for values below
  17. * minValue. Includes opacity.
  18. * @property {geo.geoColorObject} maxColor The color used for values above
  19. * maxValue. Includes opacity.
  20. * @property {geo.geoColorObject[]} colorMap The specified `colorRange` and
  21. * `opacityRange` converted into objects that include opacity.
  22. * @property {boolean} elementValues Truthy if the `value` and `opacity` are
  23. * for elements, falsy for vertices.
  24. */
  25. /**
  26. * Create a set of vertices, values at the vertices or elements, and opacities
  27. * at the vertices or elements. Create a set of triangles of indices into the
  28. * vertex array. Create a color and opacity map corresponding to the values.
  29. *
  30. * @param {geo.meshFeature} feature A mesh feature.
  31. * @param {boolean} elementValues Truthy to compute values and opacities at
  32. * elements, falsy for vertices.
  33. * @returns {geo.meshFeature.meshColoredInfo} An object with the colored mesh
  34. * information.
  35. * @memberof geo.util
  36. */
  37. function createColoredMesh(feature, elementValues) {
  38. var util = require('../util');
  39. var mesh = feature.mesh,
  40. valueFunc = feature.style.get('value'),
  41. usedFunc = feature.style('used') !== undefined ?
  42. feature.style.get('used') :
  43. function (d, i) { return util.isNonNullFinite(valueFunc(d, i)); },
  44. minmax, val, range, i, k;
  45. var meshParams = {
  46. used: usedFunc,
  47. opacity: feature.style.get('opacity'),
  48. value: valueFunc
  49. };
  50. var result = feature._createMesh(
  51. !elementValues ? meshParams : {},
  52. elementValues ? meshParams : {});
  53. result.elementValues = !!elementValues;
  54. if (!result.numVertices || !result.numElements) {
  55. return result;
  56. }
  57. var stepped = mesh.get('stepped')(result),
  58. opacityRange = mesh.get('opacityRange')(result),
  59. rangeValues = mesh.get('rangeValues')(result);
  60. result.stepped = stepped === undefined || stepped ? true : false;
  61. /* Create the min/max colors and the color array */
  62. result.colorMap = [];
  63. result.minColor = Object.assign(
  64. {a: mesh.get('minOpacity')(result) || 0},
  65. util.convertColor(mesh.get('minColor')(result)));
  66. result.maxColor = Object.assign(
  67. {a: mesh.get('maxOpacity')(result) || 0},
  68. util.convertColor(mesh.get('maxColor')(result)));
  69. mesh.get('colorRange')(result).forEach(function (clr, idx) {
  70. result.colorMap.push(Object.assign({
  71. a: opacityRange && opacityRange[idx] !== undefined ? opacityRange[idx] : 1
  72. }, util.convertColor(clr)));
  73. });
  74. /* Get min and max values */
  75. minmax = util.getMinMaxValues(result.value, mesh.get('min')(result), mesh.get('max')(result));
  76. result.minValue = minmax.min;
  77. result.maxValue = minmax.max;
  78. if (!rangeValues || !result.colorMap ||
  79. (rangeValues.length !== result.colorMap.length + 1 && (
  80. stepped || rangeValues.length !== result.colorMap.length))) {
  81. rangeValues = null;
  82. }
  83. if (rangeValues) { /* ensure increasing monotonicity */
  84. for (k = 1; k < rangeValues.length; k += 1) {
  85. if (rangeValues[k - 1] > rangeValues[k]) {
  86. rangeValues = null;
  87. break;
  88. }
  89. }
  90. }
  91. if (rangeValues) {
  92. result.minValue = rangeValues[0];
  93. result.maxValue = rangeValues[rangeValues.length - 1];
  94. }
  95. range = result.maxValue - result.minValue;
  96. if (!range) {
  97. result.colorMap = result.colorMap.slice(0, 1);
  98. range = 1;
  99. rangeValues = null;
  100. }
  101. result.rangeValues = rangeValues;
  102. result.factor = (result.colorMap.length - (stepped ? 0 : 1)) / range;
  103. /* Scale values */
  104. for (i = 0; i < result.value.length; i += 1) {
  105. val = result.value[i];
  106. if (rangeValues && val >= result.minValue && val <= result.maxValue) {
  107. for (k = 1; k < rangeValues.length; k += 1) {
  108. if (val <= rangeValues[k]) {
  109. result.value[i] = k - 1 + (val - rangeValues[k - 1]) /
  110. (rangeValues[k] - rangeValues[k - 1]);
  111. break;
  112. }
  113. }
  114. } else {
  115. result.value[i] = (val - result.minValue) * result.factor;
  116. }
  117. }
  118. return result;
  119. }
  120. module.exports = {
  121. createColoredMesh: createColoredMesh
  122. };