Symbol.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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 _symbol = require("../../util/symbol");
  21. var createSymbol = _symbol.createSymbol;
  22. var graphic = require("../../util/graphic");
  23. var _number = require("../../util/number");
  24. var parsePercent = _number.parsePercent;
  25. var _labelHelper = require("./labelHelper");
  26. var getDefaultLabel = _labelHelper.getDefaultLabel;
  27. /*
  28. * Licensed to the Apache Software Foundation (ASF) under one
  29. * or more contributor license agreements. See the NOTICE file
  30. * distributed with this work for additional information
  31. * regarding copyright ownership. The ASF licenses this file
  32. * to you under the Apache License, Version 2.0 (the
  33. * "License"); you may not use this file except in compliance
  34. * with the License. You may obtain a copy of the License at
  35. *
  36. * http://www.apache.org/licenses/LICENSE-2.0
  37. *
  38. * Unless required by applicable law or agreed to in writing,
  39. * software distributed under the License is distributed on an
  40. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  41. * KIND, either express or implied. See the License for the
  42. * specific language governing permissions and limitations
  43. * under the License.
  44. */
  45. /**
  46. * @module echarts/chart/helper/Symbol
  47. */
  48. /**
  49. * @constructor
  50. * @alias {module:echarts/chart/helper/Symbol}
  51. * @param {module:echarts/data/List} data
  52. * @param {number} idx
  53. * @extends {module:zrender/graphic/Group}
  54. */
  55. function SymbolClz(data, idx, seriesScope) {
  56. graphic.Group.call(this);
  57. this.updateData(data, idx, seriesScope);
  58. }
  59. var symbolProto = SymbolClz.prototype;
  60. /**
  61. * @public
  62. * @static
  63. * @param {module:echarts/data/List} data
  64. * @param {number} dataIndex
  65. * @return {Array.<number>} [width, height]
  66. */
  67. var getSymbolSize = SymbolClz.getSymbolSize = function (data, idx) {
  68. var symbolSize = data.getItemVisual(idx, 'symbolSize');
  69. return symbolSize instanceof Array ? symbolSize.slice() : [+symbolSize, +symbolSize];
  70. };
  71. function getScale(symbolSize) {
  72. return [symbolSize[0] / 2, symbolSize[1] / 2];
  73. }
  74. function driftSymbol(dx, dy) {
  75. this.parent.drift(dx, dy);
  76. }
  77. symbolProto._createSymbol = function (symbolType, data, idx, symbolSize, keepAspect) {
  78. // Remove paths created before
  79. this.removeAll();
  80. var color = data.getItemVisual(idx, 'color'); // var symbolPath = createSymbol(
  81. // symbolType, -0.5, -0.5, 1, 1, color
  82. // );
  83. // If width/height are set too small (e.g., set to 1) on ios10
  84. // and macOS Sierra, a circle stroke become a rect, no matter what
  85. // the scale is set. So we set width/height as 2. See #4150.
  86. var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, color, keepAspect);
  87. symbolPath.attr({
  88. z2: 100,
  89. culling: true,
  90. scale: getScale(symbolSize)
  91. }); // Rewrite drift method
  92. symbolPath.drift = driftSymbol;
  93. this._symbolType = symbolType;
  94. this.add(symbolPath);
  95. };
  96. /**
  97. * Stop animation
  98. * @param {boolean} toLastFrame
  99. */
  100. symbolProto.stopSymbolAnimation = function (toLastFrame) {
  101. this.childAt(0).stopAnimation(toLastFrame);
  102. };
  103. /**
  104. * FIXME:
  105. * Caution: This method breaks the encapsulation of this module,
  106. * but it indeed brings convenience. So do not use the method
  107. * unless you detailedly know all the implements of `Symbol`,
  108. * especially animation.
  109. *
  110. * Get symbol path element.
  111. */
  112. symbolProto.getSymbolPath = function () {
  113. return this.childAt(0);
  114. };
  115. /**
  116. * Get scale(aka, current symbol size).
  117. * Including the change caused by animation
  118. */
  119. symbolProto.getScale = function () {
  120. return this.childAt(0).scale;
  121. };
  122. /**
  123. * Highlight symbol
  124. */
  125. symbolProto.highlight = function () {
  126. this.childAt(0).trigger('emphasis');
  127. };
  128. /**
  129. * Downplay symbol
  130. */
  131. symbolProto.downplay = function () {
  132. this.childAt(0).trigger('normal');
  133. };
  134. /**
  135. * @param {number} zlevel
  136. * @param {number} z
  137. */
  138. symbolProto.setZ = function (zlevel, z) {
  139. var symbolPath = this.childAt(0);
  140. symbolPath.zlevel = zlevel;
  141. symbolPath.z = z;
  142. };
  143. symbolProto.setDraggable = function (draggable) {
  144. var symbolPath = this.childAt(0);
  145. symbolPath.draggable = draggable;
  146. symbolPath.cursor = draggable ? 'move' : symbolPath.cursor;
  147. };
  148. /**
  149. * Update symbol properties
  150. * @param {module:echarts/data/List} data
  151. * @param {number} idx
  152. * @param {Object} [seriesScope]
  153. * @param {Object} [seriesScope.itemStyle]
  154. * @param {Object} [seriesScope.hoverItemStyle]
  155. * @param {Object} [seriesScope.symbolRotate]
  156. * @param {Object} [seriesScope.symbolOffset]
  157. * @param {module:echarts/model/Model} [seriesScope.labelModel]
  158. * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]
  159. * @param {boolean} [seriesScope.hoverAnimation]
  160. * @param {Object} [seriesScope.cursorStyle]
  161. * @param {module:echarts/model/Model} [seriesScope.itemModel]
  162. * @param {string} [seriesScope.symbolInnerColor]
  163. * @param {Object} [seriesScope.fadeIn=false]
  164. */
  165. symbolProto.updateData = function (data, idx, seriesScope) {
  166. this.silent = false;
  167. var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
  168. var seriesModel = data.hostModel;
  169. var symbolSize = getSymbolSize(data, idx);
  170. var isInit = symbolType !== this._symbolType;
  171. if (isInit) {
  172. var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');
  173. this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);
  174. } else {
  175. var symbolPath = this.childAt(0);
  176. symbolPath.silent = false;
  177. graphic.updateProps(symbolPath, {
  178. scale: getScale(symbolSize)
  179. }, seriesModel, idx);
  180. }
  181. this._updateCommon(data, idx, symbolSize, seriesScope);
  182. if (isInit) {
  183. var symbolPath = this.childAt(0);
  184. var fadeIn = seriesScope && seriesScope.fadeIn;
  185. var target = {
  186. scale: symbolPath.scale.slice()
  187. };
  188. fadeIn && (target.style = {
  189. opacity: symbolPath.style.opacity
  190. });
  191. symbolPath.scale = [0, 0];
  192. fadeIn && (symbolPath.style.opacity = 0);
  193. graphic.initProps(symbolPath, target, seriesModel, idx);
  194. }
  195. this._seriesModel = seriesModel;
  196. }; // Update common properties
  197. var normalStyleAccessPath = ['itemStyle'];
  198. var emphasisStyleAccessPath = ['emphasis', 'itemStyle'];
  199. var normalLabelAccessPath = ['label'];
  200. var emphasisLabelAccessPath = ['emphasis', 'label'];
  201. /**
  202. * @param {module:echarts/data/List} data
  203. * @param {number} idx
  204. * @param {Array.<number>} symbolSize
  205. * @param {Object} [seriesScope]
  206. */
  207. symbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {
  208. var symbolPath = this.childAt(0);
  209. var seriesModel = data.hostModel;
  210. var color = data.getItemVisual(idx, 'color'); // Reset style
  211. if (symbolPath.type !== 'image') {
  212. symbolPath.useStyle({
  213. strokeNoScale: true
  214. });
  215. } else {
  216. symbolPath.setStyle({
  217. opacity: 1,
  218. shadowBlur: null,
  219. shadowOffsetX: null,
  220. shadowOffsetY: null,
  221. shadowColor: null
  222. });
  223. }
  224. var itemStyle = seriesScope && seriesScope.itemStyle;
  225. var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;
  226. var symbolOffset = seriesScope && seriesScope.symbolOffset;
  227. var labelModel = seriesScope && seriesScope.labelModel;
  228. var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;
  229. var hoverAnimation = seriesScope && seriesScope.hoverAnimation;
  230. var cursorStyle = seriesScope && seriesScope.cursorStyle;
  231. if (!seriesScope || data.hasItemOption) {
  232. var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx); // Color must be excluded.
  233. // Because symbol provide setColor individually to set fill and stroke
  234. itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);
  235. hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
  236. symbolOffset = itemModel.getShallow('symbolOffset');
  237. labelModel = itemModel.getModel(normalLabelAccessPath);
  238. hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);
  239. hoverAnimation = itemModel.getShallow('hoverAnimation');
  240. cursorStyle = itemModel.getShallow('cursor');
  241. } else {
  242. hoverItemStyle = zrUtil.extend({}, hoverItemStyle);
  243. }
  244. var elStyle = symbolPath.style;
  245. var symbolRotate = data.getItemVisual(idx, 'symbolRotate');
  246. symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);
  247. if (symbolOffset) {
  248. symbolPath.attr('position', [parsePercent(symbolOffset[0], symbolSize[0]), parsePercent(symbolOffset[1], symbolSize[1])]);
  249. }
  250. cursorStyle && symbolPath.attr('cursor', cursorStyle); // PENDING setColor before setStyle!!!
  251. symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);
  252. symbolPath.setStyle(itemStyle);
  253. var opacity = data.getItemVisual(idx, 'opacity');
  254. if (opacity != null) {
  255. elStyle.opacity = opacity;
  256. }
  257. var liftZ = data.getItemVisual(idx, 'liftZ');
  258. var z2Origin = symbolPath.__z2Origin;
  259. if (liftZ != null) {
  260. if (z2Origin == null) {
  261. symbolPath.__z2Origin = symbolPath.z2;
  262. symbolPath.z2 += liftZ;
  263. }
  264. } else if (z2Origin != null) {
  265. symbolPath.z2 = z2Origin;
  266. symbolPath.__z2Origin = null;
  267. }
  268. var useNameLabel = seriesScope && seriesScope.useNameLabel;
  269. graphic.setLabelStyle(elStyle, hoverItemStyle, labelModel, hoverLabelModel, {
  270. labelFetcher: seriesModel,
  271. labelDataIndex: idx,
  272. defaultText: getLabelDefaultText,
  273. isRectText: true,
  274. autoColor: color
  275. }); // Do not execute util needed.
  276. function getLabelDefaultText(idx, opt) {
  277. return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);
  278. }
  279. symbolPath.__symbolOriginalScale = getScale(symbolSize);
  280. symbolPath.hoverStyle = hoverItemStyle;
  281. symbolPath.highDownOnUpdate = hoverAnimation && seriesModel.isAnimationEnabled() ? highDownOnUpdate : null;
  282. graphic.setHoverStyle(symbolPath);
  283. };
  284. function highDownOnUpdate(fromState, toState) {
  285. // Do not support this hover animation util some scenario required.
  286. // Animation can only be supported in hover layer when using `el.incremetal`.
  287. if (this.incremental || this.useHoverLayer) {
  288. return;
  289. }
  290. if (toState === 'emphasis') {
  291. var scale = this.__symbolOriginalScale;
  292. var ratio = scale[1] / scale[0];
  293. var emphasisOpt = {
  294. scale: [Math.max(scale[0] * 1.1, scale[0] + 3), Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)]
  295. }; // FIXME
  296. // modify it after support stop specified animation.
  297. // toState === fromState
  298. // ? (this.stopAnimation(), this.attr(emphasisOpt))
  299. this.animateTo(emphasisOpt, 400, 'elasticOut');
  300. } else if (toState === 'normal') {
  301. this.animateTo({
  302. scale: this.__symbolOriginalScale
  303. }, 400, 'elasticOut');
  304. }
  305. }
  306. /**
  307. * @param {Function} cb
  308. * @param {Object} [opt]
  309. * @param {Object} [opt.keepLabel=true]
  310. */
  311. symbolProto.fadeOut = function (cb, opt) {
  312. var symbolPath = this.childAt(0); // Avoid mistaken hover when fading out
  313. this.silent = symbolPath.silent = true; // Not show text when animating
  314. !(opt && opt.keepLabel) && (symbolPath.style.text = null);
  315. graphic.updateProps(symbolPath, {
  316. style: {
  317. opacity: 0
  318. },
  319. scale: [0, 0]
  320. }, this._seriesModel, this.dataIndex, cb);
  321. };
  322. zrUtil.inherits(SymbolClz, graphic.Group);
  323. var _default = SymbolClz;
  324. module.exports = _default;