markerHelper.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var zrUtil = require("zrender/lib/core/util");
  20. var numberUtil = require("../../util/number");
  21. var _dataStackHelper = require("../../data/helper/dataStackHelper");
  22. var isDimensionStacked = _dataStackHelper.isDimensionStacked;
  23. /*
  24. * Licensed to the Apache Software Foundation (ASF) under one
  25. * or more contributor license agreements. See the NOTICE file
  26. * distributed with this work for additional information
  27. * regarding copyright ownership. The ASF licenses this file
  28. * to you under the Apache License, Version 2.0 (the
  29. * "License"); you may not use this file except in compliance
  30. * with the License. You may obtain a copy of the License at
  31. *
  32. * http://www.apache.org/licenses/LICENSE-2.0
  33. *
  34. * Unless required by applicable law or agreed to in writing,
  35. * software distributed under the License is distributed on an
  36. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  37. * KIND, either express or implied. See the License for the
  38. * specific language governing permissions and limitations
  39. * under the License.
  40. */
  41. var indexOf = zrUtil.indexOf;
  42. function hasXOrY(item) {
  43. return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));
  44. }
  45. function hasXAndY(item) {
  46. return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));
  47. } // Make it simple, do not visit all stacked value to count precision.
  48. // function getPrecision(data, valueAxisDim, dataIndex) {
  49. // var precision = -1;
  50. // var stackedDim = data.mapDimension(valueAxisDim);
  51. // do {
  52. // precision = Math.max(
  53. // numberUtil.getPrecision(data.get(stackedDim, dataIndex)),
  54. // precision
  55. // );
  56. // var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
  57. // if (stackedOnSeries) {
  58. // var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);
  59. // data = stackedOnSeries.getData();
  60. // dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);
  61. // stackedDim = data.getCalculationInfo('stackedDimension');
  62. // }
  63. // else {
  64. // data = null;
  65. // }
  66. // } while (data);
  67. // return precision;
  68. // }
  69. function markerTypeCalculatorWithExtent(mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex) {
  70. var coordArr = [];
  71. var stacked = isDimensionStacked(data, targetDataDim
  72. /*, otherDataDim*/
  73. );
  74. var calcDataDim = stacked ? data.getCalculationInfo('stackResultDimension') : targetDataDim;
  75. var value = numCalculate(data, calcDataDim, mlType);
  76. var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];
  77. coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);
  78. coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex); // Make it simple, do not visit all stacked value to count precision.
  79. var precision = numberUtil.getPrecision(data.get(targetDataDim, dataIndex));
  80. precision = Math.min(precision, 20);
  81. if (precision >= 0) {
  82. coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);
  83. }
  84. return coordArr;
  85. }
  86. var curry = zrUtil.curry; // TODO Specified percent
  87. var markerTypeCalculator = {
  88. /**
  89. * @method
  90. * @param {module:echarts/data/List} data
  91. * @param {string} baseAxisDim
  92. * @param {string} valueAxisDim
  93. */
  94. min: curry(markerTypeCalculatorWithExtent, 'min'),
  95. /**
  96. * @method
  97. * @param {module:echarts/data/List} data
  98. * @param {string} baseAxisDim
  99. * @param {string} valueAxisDim
  100. */
  101. max: curry(markerTypeCalculatorWithExtent, 'max'),
  102. /**
  103. * @method
  104. * @param {module:echarts/data/List} data
  105. * @param {string} baseAxisDim
  106. * @param {string} valueAxisDim
  107. */
  108. average: curry(markerTypeCalculatorWithExtent, 'average')
  109. };
  110. /**
  111. * Transform markPoint data item to format used in List by do the following
  112. * 1. Calculate statistic like `max`, `min`, `average`
  113. * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array
  114. * @param {module:echarts/model/Series} seriesModel
  115. * @param {module:echarts/coord/*} [coordSys]
  116. * @param {Object} item
  117. * @return {Object}
  118. */
  119. function dataTransform(seriesModel, item) {
  120. var data = seriesModel.getData();
  121. var coordSys = seriesModel.coordinateSystem; // 1. If not specify the position with pixel directly
  122. // 2. If `coord` is not a data array. Which uses `xAxis`,
  123. // `yAxis` to specify the coord on each dimension
  124. // parseFloat first because item.x and item.y can be percent string like '20%'
  125. if (item && !hasXAndY(item) && !zrUtil.isArray(item.coord) && coordSys) {
  126. var dims = coordSys.dimensions;
  127. var axisInfo = getAxisInfo(item, data, coordSys, seriesModel); // Clone the option
  128. // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value
  129. item = zrUtil.clone(item);
  130. if (item.type && markerTypeCalculator[item.type] && axisInfo.baseAxis && axisInfo.valueAxis) {
  131. var otherCoordIndex = indexOf(dims, axisInfo.baseAxis.dim);
  132. var targetCoordIndex = indexOf(dims, axisInfo.valueAxis.dim);
  133. item.coord = markerTypeCalculator[item.type](data, axisInfo.baseDataDim, axisInfo.valueDataDim, otherCoordIndex, targetCoordIndex); // Force to use the value of calculated value.
  134. item.value = item.coord[targetCoordIndex];
  135. } else {
  136. // FIXME Only has one of xAxis and yAxis.
  137. var coord = [item.xAxis != null ? item.xAxis : item.radiusAxis, item.yAxis != null ? item.yAxis : item.angleAxis]; // Each coord support max, min, average
  138. for (var i = 0; i < 2; i++) {
  139. if (markerTypeCalculator[coord[i]]) {
  140. coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);
  141. }
  142. }
  143. item.coord = coord;
  144. }
  145. }
  146. return item;
  147. }
  148. function getAxisInfo(item, data, coordSys, seriesModel) {
  149. var ret = {};
  150. if (item.valueIndex != null || item.valueDim != null) {
  151. ret.valueDataDim = item.valueIndex != null ? data.getDimension(item.valueIndex) : item.valueDim;
  152. ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));
  153. ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);
  154. ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);
  155. } else {
  156. ret.baseAxis = seriesModel.getBaseAxis();
  157. ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);
  158. ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);
  159. ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);
  160. }
  161. return ret;
  162. }
  163. function dataDimToCoordDim(seriesModel, dataDim) {
  164. var data = seriesModel.getData();
  165. var dimensions = data.dimensions;
  166. dataDim = data.getDimension(dataDim);
  167. for (var i = 0; i < dimensions.length; i++) {
  168. var dimItem = data.getDimensionInfo(dimensions[i]);
  169. if (dimItem.name === dataDim) {
  170. return dimItem.coordDim;
  171. }
  172. }
  173. }
  174. /**
  175. * Filter data which is out of coordinateSystem range
  176. * [dataFilter description]
  177. * @param {module:echarts/coord/*} [coordSys]
  178. * @param {Object} item
  179. * @return {boolean}
  180. */
  181. function dataFilter(coordSys, item) {
  182. // Alwalys return true if there is no coordSys
  183. return coordSys && coordSys.containData && item.coord && !hasXOrY(item) ? coordSys.containData(item.coord) : true;
  184. }
  185. function dimValueGetter(item, dimName, dataIndex, dimIndex) {
  186. // x, y, radius, angle
  187. if (dimIndex < 2) {
  188. return item.coord && item.coord[dimIndex];
  189. }
  190. return item.value;
  191. }
  192. function numCalculate(data, valueDataDim, type) {
  193. if (type === 'average') {
  194. var sum = 0;
  195. var count = 0;
  196. data.each(valueDataDim, function (val, idx) {
  197. if (!isNaN(val)) {
  198. sum += val;
  199. count++;
  200. }
  201. });
  202. return sum / count;
  203. } else if (type === 'median') {
  204. return data.getMedian(valueDataDim);
  205. } else {
  206. // max & min
  207. return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];
  208. }
  209. }
  210. exports.dataTransform = dataTransform;
  211. exports.getAxisInfo = getAxisInfo;
  212. exports.dataFilter = dataFilter;
  213. exports.dimValueGetter = dimValueGetter;
  214. exports.numCalculate = numCalculate;