VisualMapping.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  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. import * as zrUtil from 'zrender/lib/core/util';
  41. import * as zrColor from 'zrender/lib/tool/color';
  42. import { linearMap } from '../util/number';
  43. var each = zrUtil.each;
  44. var isObject = zrUtil.isObject;
  45. var CATEGORY_DEFAULT_VISUAL_INDEX = -1;
  46. var VisualMapping =
  47. /** @class */
  48. function () {
  49. function VisualMapping(option) {
  50. var mappingMethod = option.mappingMethod;
  51. var visualType = option.type;
  52. var thisOption = this.option = zrUtil.clone(option);
  53. this.type = visualType;
  54. this.mappingMethod = mappingMethod;
  55. this._normalizeData = normalizers[mappingMethod];
  56. var visualHandler = VisualMapping.visualHandlers[visualType];
  57. this.applyVisual = visualHandler.applyVisual;
  58. this.getColorMapper = visualHandler.getColorMapper;
  59. this._normalizedToVisual = visualHandler._normalizedToVisual[mappingMethod];
  60. if (mappingMethod === 'piecewise') {
  61. normalizeVisualRange(thisOption);
  62. preprocessForPiecewise(thisOption);
  63. } else if (mappingMethod === 'category') {
  64. thisOption.categories ? preprocessForSpecifiedCategory(thisOption) // categories is ordinal when thisOption.categories not specified,
  65. // which need no more preprocess except normalize visual.
  66. : normalizeVisualRange(thisOption, true);
  67. } else {
  68. // mappingMethod === 'linear' or 'fixed'
  69. zrUtil.assert(mappingMethod !== 'linear' || thisOption.dataExtent);
  70. normalizeVisualRange(thisOption);
  71. }
  72. }
  73. VisualMapping.prototype.mapValueToVisual = function (value) {
  74. var normalized = this._normalizeData(value);
  75. return this._normalizedToVisual(normalized, value);
  76. };
  77. VisualMapping.prototype.getNormalizer = function () {
  78. return zrUtil.bind(this._normalizeData, this);
  79. };
  80. /**
  81. * List available visual types.
  82. *
  83. * @public
  84. * @return {Array.<string>}
  85. */
  86. VisualMapping.listVisualTypes = function () {
  87. return zrUtil.keys(VisualMapping.visualHandlers);
  88. }; // /**
  89. // * @public
  90. // */
  91. // static addVisualHandler(name, handler) {
  92. // visualHandlers[name] = handler;
  93. // }
  94. /**
  95. * @public
  96. */
  97. VisualMapping.isValidType = function (visualType) {
  98. return VisualMapping.visualHandlers.hasOwnProperty(visualType);
  99. };
  100. /**
  101. * Convinent method.
  102. * Visual can be Object or Array or primary type.
  103. */
  104. VisualMapping.eachVisual = function (visual, callback, context) {
  105. if (zrUtil.isObject(visual)) {
  106. zrUtil.each(visual, callback, context);
  107. } else {
  108. callback.call(context, visual);
  109. }
  110. };
  111. VisualMapping.mapVisual = function (visual, callback, context) {
  112. var isPrimary;
  113. var newVisual = zrUtil.isArray(visual) ? [] : zrUtil.isObject(visual) ? {} : (isPrimary = true, null);
  114. VisualMapping.eachVisual(visual, function (v, key) {
  115. var newVal = callback.call(context, v, key);
  116. isPrimary ? newVisual = newVal : newVisual[key] = newVal;
  117. });
  118. return newVisual;
  119. };
  120. /**
  121. * Retrieve visual properties from given object.
  122. */
  123. VisualMapping.retrieveVisuals = function (obj) {
  124. var ret = {};
  125. var hasVisual;
  126. obj && each(VisualMapping.visualHandlers, function (h, visualType) {
  127. if (obj.hasOwnProperty(visualType)) {
  128. ret[visualType] = obj[visualType];
  129. hasVisual = true;
  130. }
  131. });
  132. return hasVisual ? ret : null;
  133. };
  134. /**
  135. * Give order to visual types, considering colorSaturation, colorAlpha depends on color.
  136. *
  137. * @public
  138. * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}
  139. * IF Array, like: ['color', 'symbol', 'colorSaturation']
  140. * @return {Array.<string>} Sorted visual types.
  141. */
  142. VisualMapping.prepareVisualTypes = function (visualTypes) {
  143. if (zrUtil.isArray(visualTypes)) {
  144. visualTypes = visualTypes.slice();
  145. } else if (isObject(visualTypes)) {
  146. var types_1 = [];
  147. each(visualTypes, function (item, type) {
  148. types_1.push(type);
  149. });
  150. visualTypes = types_1;
  151. } else {
  152. return [];
  153. }
  154. visualTypes.sort(function (type1, type2) {
  155. // color should be front of colorSaturation, colorAlpha, ...
  156. // symbol and symbolSize do not matter.
  157. return type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0 ? 1 : -1;
  158. });
  159. return visualTypes;
  160. };
  161. /**
  162. * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.
  163. * Other visuals are only depends on themself.
  164. */
  165. VisualMapping.dependsOn = function (visualType1, visualType2) {
  166. return visualType2 === 'color' ? !!(visualType1 && visualType1.indexOf(visualType2) === 0) : visualType1 === visualType2;
  167. };
  168. /**
  169. * @param value
  170. * @param pieceList [{value: ..., interval: [min, max]}, ...]
  171. * Always from small to big.
  172. * @param findClosestWhenOutside Default to be false
  173. * @return index
  174. */
  175. VisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {
  176. var possibleI;
  177. var abs = Infinity; // value has the higher priority.
  178. for (var i = 0, len = pieceList.length; i < len; i++) {
  179. var pieceValue = pieceList[i].value;
  180. if (pieceValue != null) {
  181. if (pieceValue === value // FIXME
  182. // It is supposed to compare value according to value type of dimension,
  183. // but currently value type can exactly be string or number.
  184. // Compromise for numeric-like string (like '12'), especially
  185. // in the case that visualMap.categories is ['22', '33'].
  186. || typeof pieceValue === 'string' && pieceValue === value + '') {
  187. return i;
  188. }
  189. findClosestWhenOutside && updatePossible(pieceValue, i);
  190. }
  191. }
  192. for (var i = 0, len = pieceList.length; i < len; i++) {
  193. var piece = pieceList[i];
  194. var interval = piece.interval;
  195. var close_1 = piece.close;
  196. if (interval) {
  197. if (interval[0] === -Infinity) {
  198. if (littleThan(close_1[1], value, interval[1])) {
  199. return i;
  200. }
  201. } else if (interval[1] === Infinity) {
  202. if (littleThan(close_1[0], interval[0], value)) {
  203. return i;
  204. }
  205. } else if (littleThan(close_1[0], interval[0], value) && littleThan(close_1[1], value, interval[1])) {
  206. return i;
  207. }
  208. findClosestWhenOutside && updatePossible(interval[0], i);
  209. findClosestWhenOutside && updatePossible(interval[1], i);
  210. }
  211. }
  212. if (findClosestWhenOutside) {
  213. return value === Infinity ? pieceList.length - 1 : value === -Infinity ? 0 : possibleI;
  214. }
  215. function updatePossible(val, index) {
  216. var newAbs = Math.abs(val - value);
  217. if (newAbs < abs) {
  218. abs = newAbs;
  219. possibleI = index;
  220. }
  221. }
  222. };
  223. VisualMapping.visualHandlers = {
  224. color: {
  225. applyVisual: makeApplyVisual('color'),
  226. getColorMapper: function () {
  227. var thisOption = this.option;
  228. return zrUtil.bind(thisOption.mappingMethod === 'category' ? function (value, isNormalized) {
  229. !isNormalized && (value = this._normalizeData(value));
  230. return doMapCategory.call(this, value);
  231. } : function (value, isNormalized, out) {
  232. // If output rgb array
  233. // which will be much faster and useful in pixel manipulation
  234. var returnRGBArray = !!out;
  235. !isNormalized && (value = this._normalizeData(value));
  236. out = zrColor.fastLerp(value, thisOption.parsedVisual, out);
  237. return returnRGBArray ? out : zrColor.stringify(out, 'rgba');
  238. }, this);
  239. },
  240. _normalizedToVisual: {
  241. linear: function (normalized) {
  242. return zrColor.stringify(zrColor.fastLerp(normalized, this.option.parsedVisual), 'rgba');
  243. },
  244. category: doMapCategory,
  245. piecewise: function (normalized, value) {
  246. var result = getSpecifiedVisual.call(this, value);
  247. if (result == null) {
  248. result = zrColor.stringify(zrColor.fastLerp(normalized, this.option.parsedVisual), 'rgba');
  249. }
  250. return result;
  251. },
  252. fixed: doMapFixed
  253. }
  254. },
  255. colorHue: makePartialColorVisualHandler(function (color, value) {
  256. return zrColor.modifyHSL(color, value);
  257. }),
  258. colorSaturation: makePartialColorVisualHandler(function (color, value) {
  259. return zrColor.modifyHSL(color, null, value);
  260. }),
  261. colorLightness: makePartialColorVisualHandler(function (color, value) {
  262. return zrColor.modifyHSL(color, null, null, value);
  263. }),
  264. colorAlpha: makePartialColorVisualHandler(function (color, value) {
  265. return zrColor.modifyAlpha(color, value);
  266. }),
  267. decal: {
  268. applyVisual: makeApplyVisual('decal'),
  269. _normalizedToVisual: {
  270. linear: null,
  271. category: doMapCategory,
  272. piecewise: null,
  273. fixed: null
  274. }
  275. },
  276. opacity: {
  277. applyVisual: makeApplyVisual('opacity'),
  278. _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
  279. },
  280. liftZ: {
  281. applyVisual: makeApplyVisual('liftZ'),
  282. _normalizedToVisual: {
  283. linear: doMapFixed,
  284. category: doMapFixed,
  285. piecewise: doMapFixed,
  286. fixed: doMapFixed
  287. }
  288. },
  289. symbol: {
  290. applyVisual: function (value, getter, setter) {
  291. var symbolCfg = this.mapValueToVisual(value);
  292. setter('symbol', symbolCfg);
  293. },
  294. _normalizedToVisual: {
  295. linear: doMapToArray,
  296. category: doMapCategory,
  297. piecewise: function (normalized, value) {
  298. var result = getSpecifiedVisual.call(this, value);
  299. if (result == null) {
  300. result = doMapToArray.call(this, normalized);
  301. }
  302. return result;
  303. },
  304. fixed: doMapFixed
  305. }
  306. },
  307. symbolSize: {
  308. applyVisual: makeApplyVisual('symbolSize'),
  309. _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
  310. }
  311. };
  312. return VisualMapping;
  313. }();
  314. function preprocessForPiecewise(thisOption) {
  315. var pieceList = thisOption.pieceList;
  316. thisOption.hasSpecialVisual = false;
  317. zrUtil.each(pieceList, function (piece, index) {
  318. piece.originIndex = index; // piece.visual is "result visual value" but not
  319. // a visual range, so it does not need to be normalized.
  320. if (piece.visual != null) {
  321. thisOption.hasSpecialVisual = true;
  322. }
  323. });
  324. }
  325. function preprocessForSpecifiedCategory(thisOption) {
  326. // Hash categories.
  327. var categories = thisOption.categories;
  328. var categoryMap = thisOption.categoryMap = {};
  329. var visual = thisOption.visual;
  330. each(categories, function (cate, index) {
  331. categoryMap[cate] = index;
  332. }); // Process visual map input.
  333. if (!zrUtil.isArray(visual)) {
  334. var visualArr_1 = [];
  335. if (zrUtil.isObject(visual)) {
  336. each(visual, function (v, cate) {
  337. var index = categoryMap[cate];
  338. visualArr_1[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;
  339. });
  340. } else {
  341. // Is primary type, represents default visual.
  342. visualArr_1[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;
  343. }
  344. visual = setVisualToOption(thisOption, visualArr_1);
  345. } // Remove categories that has no visual,
  346. // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.
  347. for (var i = categories.length - 1; i >= 0; i--) {
  348. if (visual[i] == null) {
  349. delete categoryMap[categories[i]];
  350. categories.pop();
  351. }
  352. }
  353. }
  354. function normalizeVisualRange(thisOption, isCategory) {
  355. var visual = thisOption.visual;
  356. var visualArr = [];
  357. if (zrUtil.isObject(visual)) {
  358. each(visual, function (v) {
  359. visualArr.push(v);
  360. });
  361. } else if (visual != null) {
  362. visualArr.push(visual);
  363. }
  364. var doNotNeedPair = {
  365. color: 1,
  366. symbol: 1
  367. };
  368. if (!isCategory && visualArr.length === 1 && !doNotNeedPair.hasOwnProperty(thisOption.type)) {
  369. // Do not care visualArr.length === 0, which is illegal.
  370. visualArr[1] = visualArr[0];
  371. }
  372. setVisualToOption(thisOption, visualArr);
  373. }
  374. function makePartialColorVisualHandler(applyValue) {
  375. return {
  376. applyVisual: function (value, getter, setter) {
  377. // Only used in HSL
  378. var colorChannel = this.mapValueToVisual(value); // Must not be array value
  379. setter('color', applyValue(getter('color'), colorChannel));
  380. },
  381. _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
  382. };
  383. }
  384. function doMapToArray(normalized) {
  385. var visual = this.option.visual;
  386. return visual[Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))] || {}; // TODO {}?
  387. }
  388. function makeApplyVisual(visualType) {
  389. return function (value, getter, setter) {
  390. setter(visualType, this.mapValueToVisual(value));
  391. };
  392. }
  393. function doMapCategory(normalized) {
  394. var visual = this.option.visual;
  395. return visual[this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX ? normalized % visual.length : normalized];
  396. }
  397. function doMapFixed() {
  398. // visual will be convert to array.
  399. return this.option.visual[0];
  400. }
  401. /**
  402. * Create mapped to numeric visual
  403. */
  404. function createNormalizedToNumericVisual(sourceExtent) {
  405. return {
  406. linear: function (normalized) {
  407. return linearMap(normalized, sourceExtent, this.option.visual, true);
  408. },
  409. category: doMapCategory,
  410. piecewise: function (normalized, value) {
  411. var result = getSpecifiedVisual.call(this, value);
  412. if (result == null) {
  413. result = linearMap(normalized, sourceExtent, this.option.visual, true);
  414. }
  415. return result;
  416. },
  417. fixed: doMapFixed
  418. };
  419. }
  420. function getSpecifiedVisual(value) {
  421. var thisOption = this.option;
  422. var pieceList = thisOption.pieceList;
  423. if (thisOption.hasSpecialVisual) {
  424. var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);
  425. var piece = pieceList[pieceIndex];
  426. if (piece && piece.visual) {
  427. return piece.visual[this.type];
  428. }
  429. }
  430. }
  431. function setVisualToOption(thisOption, visualArr) {
  432. thisOption.visual = visualArr;
  433. if (thisOption.type === 'color') {
  434. thisOption.parsedVisual = zrUtil.map(visualArr, function (item) {
  435. return zrColor.parse(item);
  436. });
  437. }
  438. return visualArr;
  439. }
  440. /**
  441. * Normalizers by mapping methods.
  442. */
  443. var normalizers = {
  444. linear: function (value) {
  445. return linearMap(value, this.option.dataExtent, [0, 1], true);
  446. },
  447. piecewise: function (value) {
  448. var pieceList = this.option.pieceList;
  449. var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);
  450. if (pieceIndex != null) {
  451. return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);
  452. }
  453. },
  454. category: function (value) {
  455. var index = this.option.categories ? this.option.categoryMap[value] : value; // ordinal value
  456. return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;
  457. },
  458. fixed: zrUtil.noop
  459. };
  460. function littleThan(close, a, b) {
  461. return close ? a <= b : a < b;
  462. }
  463. export default VisualMapping;