ContinuousModel.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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 VisualMapModel = require("./VisualMapModel");
  21. var numberUtil = require("../../util/number");
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. // Constant
  41. var DEFAULT_BAR_BOUND = [20, 140];
  42. var ContinuousModel = VisualMapModel.extend({
  43. type: 'visualMap.continuous',
  44. /**
  45. * @protected
  46. */
  47. defaultOption: {
  48. align: 'auto',
  49. // 'auto', 'left', 'right', 'top', 'bottom'
  50. calculable: false,
  51. // This prop effect default component type determine,
  52. // See echarts/component/visualMap/typeDefaulter.
  53. range: null,
  54. // selected range. In default case `range` is [min, max]
  55. // and can auto change along with modification of min max,
  56. // util use specifid a range.
  57. realtime: true,
  58. // Whether realtime update.
  59. itemHeight: null,
  60. // The length of the range control edge.
  61. itemWidth: null,
  62. // The length of the other side.
  63. hoverLink: true,
  64. // Enable hover highlight.
  65. hoverLinkDataSize: null,
  66. // The size of hovered data.
  67. hoverLinkOnHandle: null // Whether trigger hoverLink when hover handle.
  68. // If not specified, follow the value of `realtime`.
  69. },
  70. /**
  71. * @override
  72. */
  73. optionUpdated: function (newOption, isInit) {
  74. ContinuousModel.superApply(this, 'optionUpdated', arguments);
  75. this.resetExtent();
  76. this.resetVisual(function (mappingOption) {
  77. mappingOption.mappingMethod = 'linear';
  78. mappingOption.dataExtent = this.getExtent();
  79. });
  80. this._resetRange();
  81. },
  82. /**
  83. * @protected
  84. * @override
  85. */
  86. resetItemSize: function () {
  87. ContinuousModel.superApply(this, 'resetItemSize', arguments);
  88. var itemSize = this.itemSize;
  89. this._orient === 'horizontal' && itemSize.reverse();
  90. (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);
  91. (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);
  92. },
  93. /**
  94. * @private
  95. */
  96. _resetRange: function () {
  97. var dataExtent = this.getExtent();
  98. var range = this.option.range;
  99. if (!range || range.auto) {
  100. // `range` should always be array (so we dont use other
  101. // value like 'auto') for user-friend. (consider getOption).
  102. dataExtent.auto = 1;
  103. this.option.range = dataExtent;
  104. } else if (zrUtil.isArray(range)) {
  105. if (range[0] > range[1]) {
  106. range.reverse();
  107. }
  108. range[0] = Math.max(range[0], dataExtent[0]);
  109. range[1] = Math.min(range[1], dataExtent[1]);
  110. }
  111. },
  112. /**
  113. * @protected
  114. * @override
  115. */
  116. completeVisualOption: function () {
  117. VisualMapModel.prototype.completeVisualOption.apply(this, arguments);
  118. zrUtil.each(this.stateList, function (state) {
  119. var symbolSize = this.option.controller[state].symbolSize;
  120. if (symbolSize && symbolSize[0] !== symbolSize[1]) {
  121. symbolSize[0] = 0; // For good looking.
  122. }
  123. }, this);
  124. },
  125. /**
  126. * @override
  127. */
  128. setSelected: function (selected) {
  129. this.option.range = selected.slice();
  130. this._resetRange();
  131. },
  132. /**
  133. * @public
  134. */
  135. getSelected: function () {
  136. var dataExtent = this.getExtent();
  137. var dataInterval = numberUtil.asc((this.get('range') || []).slice()); // Clamp
  138. dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);
  139. dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);
  140. dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);
  141. dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);
  142. return dataInterval;
  143. },
  144. /**
  145. * @override
  146. */
  147. getValueState: function (value) {
  148. var range = this.option.range;
  149. var dataExtent = this.getExtent(); // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.
  150. // range[1] is processed likewise.
  151. return (range[0] <= dataExtent[0] || range[0] <= value) && (range[1] >= dataExtent[1] || value <= range[1]) ? 'inRange' : 'outOfRange';
  152. },
  153. /**
  154. * @params {Array.<number>} range target value: range[0] <= value && value <= range[1]
  155. * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]
  156. */
  157. findTargetDataIndices: function (range) {
  158. var result = [];
  159. this.eachTargetSeries(function (seriesModel) {
  160. var dataIndices = [];
  161. var data = seriesModel.getData();
  162. data.each(this.getDataDimension(data), function (value, dataIndex) {
  163. range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);
  164. }, this);
  165. result.push({
  166. seriesId: seriesModel.id,
  167. dataIndex: dataIndices
  168. });
  169. }, this);
  170. return result;
  171. },
  172. /**
  173. * @implement
  174. */
  175. getVisualMeta: function (getColorVisual) {
  176. var oVals = getColorStopValues(this, 'outOfRange', this.getExtent());
  177. var iVals = getColorStopValues(this, 'inRange', this.option.range.slice());
  178. var stops = [];
  179. function setStop(value, valueState) {
  180. stops.push({
  181. value: value,
  182. color: getColorVisual(value, valueState)
  183. });
  184. } // Format to: outOfRange -- inRange -- outOfRange.
  185. var iIdx = 0;
  186. var oIdx = 0;
  187. var iLen = iVals.length;
  188. var oLen = oVals.length;
  189. for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) {
  190. // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored.
  191. if (oVals[oIdx] < iVals[iIdx]) {
  192. setStop(oVals[oIdx], 'outOfRange');
  193. }
  194. }
  195. for (var first = 1; iIdx < iLen; iIdx++, first = 0) {
  196. // If range is full, value beyond min, max will be clamped.
  197. // make a singularity
  198. first && stops.length && setStop(iVals[iIdx], 'outOfRange');
  199. setStop(iVals[iIdx], 'inRange');
  200. }
  201. for (var first = 1; oIdx < oLen; oIdx++) {
  202. if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) {
  203. // make a singularity
  204. if (first) {
  205. stops.length && setStop(stops[stops.length - 1].value, 'outOfRange');
  206. first = 0;
  207. }
  208. setStop(oVals[oIdx], 'outOfRange');
  209. }
  210. }
  211. var stopsLen = stops.length;
  212. return {
  213. stops: stops,
  214. outerColors: [stopsLen ? stops[0].color : 'transparent', stopsLen ? stops[stopsLen - 1].color : 'transparent']
  215. };
  216. }
  217. });
  218. function getColorStopValues(visualMapModel, valueState, dataExtent) {
  219. if (dataExtent[0] === dataExtent[1]) {
  220. return dataExtent.slice();
  221. } // When using colorHue mapping, it is not linear color any more.
  222. // Moreover, canvas gradient seems not to be accurate linear.
  223. // FIXME
  224. // Should be arbitrary value 100? or based on pixel size?
  225. var count = 200;
  226. var step = (dataExtent[1] - dataExtent[0]) / count;
  227. var value = dataExtent[0];
  228. var stopValues = [];
  229. for (var i = 0; i <= count && value < dataExtent[1]; i++) {
  230. stopValues.push(value);
  231. value += step;
  232. }
  233. stopValues.push(dataExtent[1]);
  234. return stopValues;
  235. }
  236. var _default = ContinuousModel;
  237. module.exports = _default;