TreeView.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. var zrUtil = require("zrender/lib/core/util");
  2. var graphic = require("../../util/graphic");
  3. var SymbolClz = require("../helper/Symbol");
  4. var _layoutHelper = require("./layoutHelper");
  5. var radialCoordinate = _layoutHelper.radialCoordinate;
  6. var echarts = require("../../echarts");
  7. /**
  8. * @file This file used to draw tree view
  9. */
  10. var _default = echarts.extendChartView({
  11. type: 'tree',
  12. /**
  13. * Init the chart
  14. * @override
  15. * @param {module:echarts/model/Global} ecModel
  16. * @param {module:echarts/ExtensionAPI} api
  17. */
  18. init: function (ecModel, api) {
  19. /**
  20. * @private
  21. * @type {module:echarts/data/Tree}
  22. */
  23. this._oldTree;
  24. /**
  25. * @private
  26. * @type {module:zrender/container/Group}
  27. */
  28. this._mainGroup = new graphic.Group();
  29. this.group.add(this._mainGroup);
  30. },
  31. render: function (seriesModel, ecModel, api, payload) {
  32. var data = seriesModel.getData();
  33. var layoutInfo = seriesModel.layoutInfo;
  34. var group = this._mainGroup;
  35. var layout = seriesModel.get('layout');
  36. if (layout === 'radial') {
  37. group.attr('position', [layoutInfo.x + layoutInfo.width / 2, layoutInfo.y + layoutInfo.height / 2]);
  38. } else {
  39. group.attr('position', [layoutInfo.x, layoutInfo.y]);
  40. }
  41. var oldData = this._data;
  42. var seriesScope = {
  43. expandAndCollapse: seriesModel.get('expandAndCollapse'),
  44. layout: layout,
  45. orient: seriesModel.get('orient'),
  46. curvature: seriesModel.get('lineStyle.normal.curveness'),
  47. symbolRotate: seriesModel.get('symbolRotate'),
  48. symbolOffset: seriesModel.get('symbolOffset'),
  49. hoverAnimation: seriesModel.get('hoverAnimation'),
  50. useNameLabel: true,
  51. fadeIn: true
  52. };
  53. data.diff(oldData).add(function (newIdx) {
  54. if (symbolNeedsDraw(data, newIdx)) {
  55. // create node and edge
  56. updateNode(data, newIdx, null, group, seriesModel, seriesScope);
  57. }
  58. }).update(function (newIdx, oldIdx) {
  59. var symbolEl = oldData.getItemGraphicEl(oldIdx);
  60. if (!symbolNeedsDraw(data, newIdx)) {
  61. symbolEl && removeNode(data, newIdx, symbolEl, group, seriesModel, seriesScope);
  62. return;
  63. } // update node and edge
  64. updateNode(data, newIdx, symbolEl, group, seriesModel, seriesScope);
  65. }).remove(function (oldIdx) {
  66. var symbolEl = oldData.getItemGraphicEl(oldIdx);
  67. removeNode(data, oldIdx, symbolEl, group, seriesModel, seriesScope);
  68. }).execute();
  69. if (seriesScope.expandAndCollapse === true) {
  70. data.eachItemGraphicEl(function (el, dataIndex) {
  71. el.off('click').on('click', function () {
  72. api.dispatchAction({
  73. type: 'treeExpandAndCollapse',
  74. seriesId: seriesModel.id,
  75. dataIndex: dataIndex
  76. });
  77. });
  78. });
  79. }
  80. this._data = data;
  81. },
  82. dispose: function () {},
  83. remove: function () {
  84. this._mainGroup.removeAll();
  85. this._data = null;
  86. }
  87. });
  88. function symbolNeedsDraw(data, dataIndex) {
  89. var layout = data.getItemLayout(dataIndex);
  90. return layout && !isNaN(layout.x) && !isNaN(layout.y) && data.getItemVisual(dataIndex, 'symbol') !== 'none';
  91. }
  92. function getTreeNodeStyle(node, itemModel, seriesScope) {
  93. seriesScope.itemModel = itemModel;
  94. seriesScope.itemStyle = itemModel.getModel('itemStyle.normal').getItemStyle();
  95. seriesScope.hoverItemStyle = itemModel.getModel('itemStyle.emphasis').getItemStyle();
  96. seriesScope.lineStyle = itemModel.getModel('lineStyle.normal').getLineStyle();
  97. seriesScope.labelModel = itemModel.getModel('label.normal');
  98. seriesScope.hoverLabelModel = itemModel.getModel('label.emphasis');
  99. if (node.isExpand === false && node.children.length !== 0) {
  100. seriesScope.symbolInnerColor = seriesScope.itemStyle.fill;
  101. } else {
  102. seriesScope.symbolInnerColor = '#fff';
  103. }
  104. return seriesScope;
  105. }
  106. function updateNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {
  107. var isInit = !symbolEl;
  108. var node = data.tree.getNodeByDataIndex(dataIndex);
  109. var itemModel = node.getModel();
  110. var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);
  111. var virtualRoot = data.tree.root;
  112. var source = node.parentNode === virtualRoot ? node : node.parentNode || node;
  113. var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex);
  114. var sourceLayout = source.getLayout();
  115. var sourceOldLayout = sourceSymbolEl ? {
  116. x: sourceSymbolEl.position[0],
  117. y: sourceSymbolEl.position[1],
  118. rawX: sourceSymbolEl.__radialOldRawX,
  119. rawY: sourceSymbolEl.__radialOldRawY
  120. } : sourceLayout;
  121. var targetLayout = node.getLayout();
  122. if (isInit) {
  123. symbolEl = new SymbolClz(data, dataIndex, seriesScope);
  124. symbolEl.attr('position', [sourceOldLayout.x, sourceOldLayout.y]);
  125. } else {
  126. symbolEl.updateData(data, dataIndex, seriesScope);
  127. }
  128. symbolEl.__radialOldRawX = symbolEl.__radialRawX;
  129. symbolEl.__radialOldRawY = symbolEl.__radialRawY;
  130. symbolEl.__radialRawX = targetLayout.rawX;
  131. symbolEl.__radialRawY = targetLayout.rawY;
  132. group.add(symbolEl);
  133. data.setItemGraphicEl(dataIndex, symbolEl);
  134. graphic.updateProps(symbolEl, {
  135. position: [targetLayout.x, targetLayout.y]
  136. }, seriesModel);
  137. var symbolPath = symbolEl.getSymbolPath();
  138. if (seriesScope.layout === 'radial') {
  139. var realRoot = virtualRoot.children[0];
  140. var rootLayout = realRoot.getLayout();
  141. var length = realRoot.children.length;
  142. var rad;
  143. var isLeft;
  144. if (targetLayout.x === rootLayout.x && node.isExpand === true) {
  145. var center = {};
  146. center.x = (realRoot.children[0].getLayout().x + realRoot.children[length - 1].getLayout().x) / 2;
  147. center.y = (realRoot.children[0].getLayout().y + realRoot.children[length - 1].getLayout().y) / 2;
  148. rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x);
  149. if (rad < 0) {
  150. rad = Math.PI * 2 + rad;
  151. }
  152. isLeft = center.x < rootLayout.x;
  153. if (isLeft) {
  154. rad = rad - Math.PI;
  155. }
  156. } else {
  157. rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x);
  158. if (rad < 0) {
  159. rad = Math.PI * 2 + rad;
  160. }
  161. if (node.children.length === 0 || node.children.length !== 0 && node.isExpand === false) {
  162. isLeft = targetLayout.x < rootLayout.x;
  163. if (isLeft) {
  164. rad = rad - Math.PI;
  165. }
  166. } else {
  167. isLeft = targetLayout.x > rootLayout.x;
  168. if (!isLeft) {
  169. rad = rad - Math.PI;
  170. }
  171. }
  172. }
  173. var textPosition = isLeft ? 'left' : 'right';
  174. symbolPath.setStyle({
  175. textPosition: textPosition,
  176. textRotation: -rad,
  177. textOrigin: 'center',
  178. verticalAlign: 'middle'
  179. });
  180. }
  181. if (node.parentNode && node.parentNode !== virtualRoot) {
  182. var edge = symbolEl.__edge;
  183. if (!edge) {
  184. edge = symbolEl.__edge = new graphic.BezierCurve({
  185. shape: getEdgeShape(seriesScope, sourceOldLayout, sourceOldLayout),
  186. style: zrUtil.defaults({
  187. opacity: 0
  188. }, seriesScope.lineStyle)
  189. });
  190. }
  191. graphic.updateProps(edge, {
  192. shape: getEdgeShape(seriesScope, sourceLayout, targetLayout),
  193. style: {
  194. opacity: 1
  195. }
  196. }, seriesModel);
  197. group.add(edge);
  198. }
  199. }
  200. function removeNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {
  201. var node = data.tree.getNodeByDataIndex(dataIndex);
  202. var virtualRoot = data.tree.root;
  203. var itemModel = node.getModel();
  204. var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);
  205. var source = node.parentNode === virtualRoot ? node : node.parentNode || node;
  206. var sourceLayout;
  207. while (sourceLayout = source.getLayout(), sourceLayout == null) {
  208. source = source.parentNode === virtualRoot ? source : source.parentNode || source;
  209. }
  210. graphic.updateProps(symbolEl, {
  211. position: [sourceLayout.x + 1, sourceLayout.y + 1]
  212. }, seriesModel, function () {
  213. group.remove(symbolEl);
  214. data.setItemGraphicEl(dataIndex, null);
  215. });
  216. symbolEl.fadeOut(null, {
  217. keepLabel: true
  218. });
  219. var edge = symbolEl.__edge;
  220. if (edge) {
  221. graphic.updateProps(edge, {
  222. shape: getEdgeShape(seriesScope, sourceLayout, sourceLayout),
  223. style: {
  224. opacity: 0
  225. }
  226. }, seriesModel, function () {
  227. group.remove(edge);
  228. });
  229. }
  230. }
  231. function getEdgeShape(seriesScope, sourceLayout, targetLayout) {
  232. var cpx1;
  233. var cpy1;
  234. var cpx2;
  235. var cpy2;
  236. var orient = seriesScope.orient;
  237. if (seriesScope.layout === 'radial') {
  238. var x1 = sourceLayout.rawX;
  239. var y1 = sourceLayout.rawY;
  240. var x2 = targetLayout.rawX;
  241. var y2 = targetLayout.rawY;
  242. var radialCoor1 = radialCoordinate(x1, y1);
  243. var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * seriesScope.curvature);
  244. var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * seriesScope.curvature);
  245. var radialCoor4 = radialCoordinate(x2, y2);
  246. return {
  247. x1: radialCoor1.x,
  248. y1: radialCoor1.y,
  249. x2: radialCoor4.x,
  250. y2: radialCoor4.y,
  251. cpx1: radialCoor2.x,
  252. cpy1: radialCoor2.y,
  253. cpx2: radialCoor3.x,
  254. cpy2: radialCoor3.y
  255. };
  256. } else {
  257. var x1 = sourceLayout.x;
  258. var y1 = sourceLayout.y;
  259. var x2 = targetLayout.x;
  260. var y2 = targetLayout.y;
  261. if (orient === 'horizontal') {
  262. cpx1 = x1 + (x2 - x1) * seriesScope.curvature;
  263. cpy1 = y1;
  264. cpx2 = x2 + (x1 - x2) * seriesScope.curvature;
  265. cpy2 = y2;
  266. }
  267. if (orient === 'vertical') {
  268. cpx1 = x1;
  269. cpy1 = y1 + (y2 - y1) * seriesScope.curvature;
  270. cpx2 = x2;
  271. cpy2 = y2 + (y1 - y2) * seriesScope.curvature;
  272. }
  273. return {
  274. x1: x1,
  275. y1: y1,
  276. x2: x2,
  277. y2: y2,
  278. cpx1: cpx1,
  279. cpy1: cpy1,
  280. cpx2: cpx2,
  281. cpy2: cpy2
  282. };
  283. }
  284. }
  285. module.exports = _default;