GraphView.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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 { __extends } from "tslib";
  41. import SymbolDraw from '../helper/SymbolDraw.js';
  42. import LineDraw from '../helper/LineDraw.js';
  43. import RoamController from '../../component/helper/RoamController.js';
  44. import { updateViewOnZoom, updateViewOnPan } from '../../component/helper/roamHelper.js';
  45. import * as graphic from '../../util/graphic.js';
  46. import adjustEdge from './adjustEdge.js';
  47. import { getNodeGlobalScale } from './graphHelper.js';
  48. import ChartView from '../../view/Chart.js';
  49. import { getECData } from '../../util/innerStore.js';
  50. import { simpleLayoutEdge } from './simpleLayoutHelper.js';
  51. import { circularLayout, rotateNodeLabel } from './circularLayoutHelper.js';
  52. import { clone, extend } from 'zrender/lib/core/util.js';
  53. import ECLinePath from '../helper/LinePath.js';
  54. import { getThumbnailBridge } from '../../component/helper/thumbnailBridge.js';
  55. function isViewCoordSys(coordSys) {
  56. return coordSys.type === 'view';
  57. }
  58. var GraphView = /** @class */function (_super) {
  59. __extends(GraphView, _super);
  60. function GraphView() {
  61. var _this = _super !== null && _super.apply(this, arguments) || this;
  62. _this.type = GraphView.type;
  63. return _this;
  64. }
  65. GraphView.prototype.init = function (ecModel, api) {
  66. var symbolDraw = new SymbolDraw();
  67. var lineDraw = new LineDraw();
  68. var group = this.group;
  69. var mainGroup = new graphic.Group();
  70. this._controller = new RoamController(api.getZr());
  71. this._controllerHost = {
  72. target: mainGroup
  73. };
  74. mainGroup.add(symbolDraw.group);
  75. mainGroup.add(lineDraw.group);
  76. group.add(mainGroup);
  77. this._symbolDraw = symbolDraw;
  78. this._lineDraw = lineDraw;
  79. this._mainGroup = mainGroup;
  80. this._firstRender = true;
  81. };
  82. GraphView.prototype.render = function (seriesModel, ecModel, api) {
  83. var _this = this;
  84. var coordSys = seriesModel.coordinateSystem;
  85. var isForceLayout = false;
  86. this._model = seriesModel;
  87. this._api = api;
  88. this._active = true;
  89. var thumbnailInfo = this._getThumbnailInfo();
  90. if (thumbnailInfo) {
  91. thumbnailInfo.bridge.reset(api);
  92. }
  93. var symbolDraw = this._symbolDraw;
  94. var lineDraw = this._lineDraw;
  95. if (isViewCoordSys(coordSys)) {
  96. var groupNewProp = {
  97. x: coordSys.x,
  98. y: coordSys.y,
  99. scaleX: coordSys.scaleX,
  100. scaleY: coordSys.scaleY
  101. };
  102. if (this._firstRender) {
  103. this._mainGroup.attr(groupNewProp);
  104. } else {
  105. graphic.updateProps(this._mainGroup, groupNewProp, seriesModel);
  106. }
  107. }
  108. // Fix edge contact point with node
  109. adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel));
  110. var data = seriesModel.getData();
  111. symbolDraw.updateData(data);
  112. var edgeData = seriesModel.getEdgeData();
  113. // TODO: TYPE
  114. lineDraw.updateData(edgeData);
  115. this._updateNodeAndLinkScale();
  116. this._updateController(null, seriesModel, api);
  117. clearTimeout(this._layoutTimeout);
  118. var forceLayout = seriesModel.forceLayout;
  119. var layoutAnimation = seriesModel.get(['force', 'layoutAnimation']);
  120. if (forceLayout) {
  121. isForceLayout = true;
  122. this._startForceLayoutIteration(forceLayout, api, layoutAnimation);
  123. }
  124. var layout = seriesModel.get('layout');
  125. data.graph.eachNode(function (node) {
  126. var idx = node.dataIndex;
  127. var el = node.getGraphicEl();
  128. var itemModel = node.getModel();
  129. if (!el) {
  130. return;
  131. }
  132. // Update draggable
  133. el.off('drag').off('dragend');
  134. var draggable = itemModel.get('draggable');
  135. if (draggable) {
  136. el.on('drag', function (e) {
  137. switch (layout) {
  138. case 'force':
  139. forceLayout.warmUp();
  140. !_this._layouting && _this._startForceLayoutIteration(forceLayout, api, layoutAnimation);
  141. forceLayout.setFixed(idx);
  142. // Write position back to layout
  143. data.setItemLayout(idx, [el.x, el.y]);
  144. break;
  145. case 'circular':
  146. data.setItemLayout(idx, [el.x, el.y]);
  147. // mark node fixed
  148. node.setLayout({
  149. fixed: true
  150. }, true);
  151. // recalculate circular layout
  152. circularLayout(seriesModel, 'symbolSize', node, [e.offsetX, e.offsetY]);
  153. _this.updateLayout(seriesModel);
  154. break;
  155. case 'none':
  156. default:
  157. data.setItemLayout(idx, [el.x, el.y]);
  158. // update edge
  159. simpleLayoutEdge(seriesModel.getGraph(), seriesModel);
  160. _this.updateLayout(seriesModel);
  161. break;
  162. }
  163. }).on('dragend', function () {
  164. if (forceLayout) {
  165. forceLayout.setUnfixed(idx);
  166. }
  167. });
  168. }
  169. el.setDraggable(draggable, !!itemModel.get('cursor'));
  170. var focus = itemModel.get(['emphasis', 'focus']);
  171. if (focus === 'adjacency') {
  172. getECData(el).focus = node.getAdjacentDataIndices();
  173. }
  174. });
  175. data.graph.eachEdge(function (edge) {
  176. var el = edge.getGraphicEl();
  177. var focus = edge.getModel().get(['emphasis', 'focus']);
  178. if (!el) {
  179. return;
  180. }
  181. if (focus === 'adjacency') {
  182. getECData(el).focus = {
  183. edge: [edge.dataIndex],
  184. node: [edge.node1.dataIndex, edge.node2.dataIndex]
  185. };
  186. }
  187. });
  188. var circularRotateLabel = seriesModel.get('layout') === 'circular' && seriesModel.get(['circular', 'rotateLabel']);
  189. var cx = data.getLayout('cx');
  190. var cy = data.getLayout('cy');
  191. data.graph.eachNode(function (node) {
  192. rotateNodeLabel(node, circularRotateLabel, cx, cy);
  193. });
  194. this._firstRender = false;
  195. // Force layout will render thumbnail when layout is finished.
  196. if (!isForceLayout) {
  197. this._renderThumbnail(seriesModel, api, this._symbolDraw, this._lineDraw);
  198. }
  199. };
  200. GraphView.prototype.dispose = function () {
  201. this.remove();
  202. this._controller && this._controller.dispose();
  203. this._controllerHost = null;
  204. };
  205. GraphView.prototype._startForceLayoutIteration = function (forceLayout, api, layoutAnimation) {
  206. var self = this;
  207. var firstRendered = false;
  208. (function step() {
  209. forceLayout.step(function (stopped) {
  210. self.updateLayout(self._model);
  211. if (stopped || !firstRendered) {
  212. firstRendered = true;
  213. self._renderThumbnail(self._model, api, self._symbolDraw, self._lineDraw);
  214. }
  215. (self._layouting = !stopped) && (layoutAnimation ? self._layoutTimeout = setTimeout(step, 16) : step());
  216. });
  217. })();
  218. };
  219. GraphView.prototype._updateController = function (clipRect, seriesModel, api) {
  220. var controller = this._controller;
  221. var controllerHost = this._controllerHost;
  222. var coordSys = seriesModel.coordinateSystem;
  223. if (!isViewCoordSys(coordSys)) {
  224. controller.disable();
  225. return;
  226. }
  227. controller.enable(seriesModel.get('roam'), {
  228. api: api,
  229. zInfo: {
  230. component: seriesModel
  231. },
  232. triggerInfo: {
  233. roamTrigger: seriesModel.get('roamTrigger'),
  234. isInSelf: function (e, x, y) {
  235. return coordSys.containPoint([x, y]);
  236. },
  237. isInClip: function (e, x, y) {
  238. return !clipRect || clipRect.contain(x, y);
  239. }
  240. }
  241. });
  242. controllerHost.zoomLimit = seriesModel.get('scaleLimit');
  243. controllerHost.zoom = coordSys.getZoom();
  244. controller.off('pan').off('zoom').on('pan', function (e) {
  245. api.dispatchAction({
  246. seriesId: seriesModel.id,
  247. type: 'graphRoam',
  248. dx: e.dx,
  249. dy: e.dy
  250. });
  251. }).on('zoom', function (e) {
  252. api.dispatchAction({
  253. seriesId: seriesModel.id,
  254. type: 'graphRoam',
  255. zoom: e.scale,
  256. originX: e.originX,
  257. originY: e.originY
  258. });
  259. });
  260. };
  261. /**
  262. * A performance shortcut - called by action handler to update the view directly
  263. * without any data/visual processing (which are assumed to be unchanged), while
  264. * ensuring consistent behavior between internal and external action triggers.
  265. */
  266. GraphView.prototype.updateViewOnPan = function (seriesModel, api, params) {
  267. if (!this._active) {
  268. return;
  269. }
  270. updateViewOnPan(this._controllerHost, params.dx, params.dy);
  271. this._updateThumbnailWindow();
  272. };
  273. /**
  274. * A performance shortcut - called by action handler to update the view directly
  275. * without any data/visual processing (which are assumed to be unchanged), while
  276. * ensuring consistent behavior between internal and external action triggers.
  277. */
  278. GraphView.prototype.updateViewOnZoom = function (seriesModel, api, params) {
  279. if (!this._active) {
  280. return;
  281. }
  282. updateViewOnZoom(this._controllerHost, params.zoom, params.originX, params.originY);
  283. this._updateNodeAndLinkScale();
  284. adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel));
  285. this._lineDraw.updateLayout();
  286. // Only update label layout on zoom
  287. api.updateLabelLayout();
  288. this._updateThumbnailWindow();
  289. };
  290. GraphView.prototype._updateNodeAndLinkScale = function () {
  291. var seriesModel = this._model;
  292. var data = seriesModel.getData();
  293. var nodeScale = getNodeGlobalScale(seriesModel);
  294. data.eachItemGraphicEl(function (el, idx) {
  295. el && el.setSymbolScale(nodeScale);
  296. });
  297. };
  298. GraphView.prototype.updateLayout = function (seriesModel) {
  299. if (!this._active) {
  300. return;
  301. }
  302. adjustEdge(seriesModel.getGraph(), getNodeGlobalScale(seriesModel));
  303. this._symbolDraw.updateLayout();
  304. this._lineDraw.updateLayout();
  305. };
  306. GraphView.prototype.remove = function () {
  307. this._active = false;
  308. clearTimeout(this._layoutTimeout);
  309. this._layouting = false;
  310. this._layoutTimeout = null;
  311. this._symbolDraw && this._symbolDraw.remove();
  312. this._lineDraw && this._lineDraw.remove();
  313. this._controller && this._controller.disable();
  314. };
  315. /**
  316. * Get thumbnail data structure only if supported.
  317. */
  318. GraphView.prototype._getThumbnailInfo = function () {
  319. var model = this._model;
  320. var coordSys = model.coordinateSystem;
  321. if (coordSys.type !== 'view') {
  322. return;
  323. }
  324. var bridge = getThumbnailBridge(model);
  325. if (!bridge) {
  326. return;
  327. }
  328. return {
  329. bridge: bridge,
  330. coordSys: coordSys
  331. };
  332. };
  333. GraphView.prototype._updateThumbnailWindow = function () {
  334. var info = this._getThumbnailInfo();
  335. if (info) {
  336. info.bridge.updateWindow(info.coordSys.transform, this._api);
  337. }
  338. };
  339. GraphView.prototype._renderThumbnail = function (seriesModel, api, symbolDraw, lineDraw) {
  340. var info = this._getThumbnailInfo();
  341. if (!info) {
  342. return;
  343. }
  344. var bridgeGroup = new graphic.Group();
  345. var symbolNodes = symbolDraw.group.children();
  346. var lineNodes = lineDraw.group.children();
  347. var lineGroup = new graphic.Group();
  348. var symbolGroup = new graphic.Group();
  349. bridgeGroup.add(symbolGroup);
  350. bridgeGroup.add(lineGroup);
  351. // TODO: reuse elemenents for performance in large graph?
  352. for (var i = 0; i < symbolNodes.length; i++) {
  353. var node = symbolNodes[i];
  354. var sub = node.children()[0];
  355. var x = node.x;
  356. var y = node.y;
  357. var subShape = clone(sub.shape);
  358. var shape = extend(subShape, {
  359. width: sub.scaleX,
  360. height: sub.scaleY,
  361. x: x - sub.scaleX / 2,
  362. y: y - sub.scaleY / 2
  363. });
  364. var style = clone(sub.style);
  365. var subThumbnail = new sub.constructor({
  366. shape: shape,
  367. style: style,
  368. z2: 151
  369. });
  370. symbolGroup.add(subThumbnail);
  371. }
  372. for (var i = 0; i < lineNodes.length; i++) {
  373. var node = lineNodes[i];
  374. var line = node.children()[0];
  375. var style = clone(line.style);
  376. var shape = clone(line.shape);
  377. var lineThumbnail = new ECLinePath({
  378. style: style,
  379. shape: shape,
  380. z2: 151
  381. });
  382. lineGroup.add(lineThumbnail);
  383. }
  384. info.bridge.renderContent({
  385. api: api,
  386. roamType: seriesModel.get('roam'),
  387. viewportRect: null,
  388. group: bridgeGroup,
  389. targetTrans: info.coordSys.transform
  390. });
  391. };
  392. GraphView.type = 'graph';
  393. return GraphView;
  394. }(ChartView);
  395. export default GraphView;