plot.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Plot = exports.PLOT_CONTAINER_OPTIONS = void 0;
  4. var tslib_1 = require("tslib");
  5. var event_emitter_1 = tslib_1.__importDefault(require("@antv/event-emitter"));
  6. var g2_1 = require("@antv/g2");
  7. var util_1 = require("@antv/util");
  8. var size_sensor_1 = require("size-sensor");
  9. var utils_1 = require("../utils");
  10. var SOURCE_ATTRIBUTE_NAME = 'data-chart-source-type';
  11. /** plot 图表容器的配置 */
  12. exports.PLOT_CONTAINER_OPTIONS = [
  13. 'padding',
  14. 'appendPadding',
  15. 'renderer',
  16. 'pixelRatio',
  17. 'syncViewPadding',
  18. 'supportCSSTransform',
  19. 'limitInPlot',
  20. ];
  21. /**
  22. * 所有 plot 的基类
  23. */
  24. var Plot = /** @class */ (function (_super) {
  25. tslib_1.__extends(Plot, _super);
  26. function Plot(container, options) {
  27. var _this = _super.call(this) || this;
  28. _this.container = typeof container === 'string' ? document.getElementById(container) : container;
  29. _this.options = (0, utils_1.deepAssign)({}, _this.getDefaultOptions(), options);
  30. _this.createG2();
  31. _this.bindEvents();
  32. return _this;
  33. }
  34. /**
  35. * 获取默认的 options 配置项
  36. * 每个组件都可以复写
  37. */
  38. Plot.getDefaultOptions = function () {
  39. return {
  40. renderer: 'canvas',
  41. xAxis: {
  42. nice: true,
  43. label: {
  44. autoRotate: false,
  45. autoHide: { type: 'equidistance', cfg: { minGap: 6 } },
  46. },
  47. },
  48. yAxis: {
  49. nice: true,
  50. label: {
  51. autoHide: true,
  52. autoRotate: false,
  53. },
  54. },
  55. animation: true,
  56. };
  57. };
  58. /**
  59. * 创建 G2 实例
  60. */
  61. Plot.prototype.createG2 = function () {
  62. var _a = this.options, width = _a.width, height = _a.height, defaultInteractions = _a.defaultInteractions;
  63. this.chart = new g2_1.Chart(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ container: this.container, autoFit: false }, this.getChartSize(width, height)), { localRefresh: false }), (0, utils_1.pick)(this.options, exports.PLOT_CONTAINER_OPTIONS)), { defaultInteractions: defaultInteractions }));
  64. // 给容器增加标识,知道图表的来源区别于 G2
  65. this.container.setAttribute(SOURCE_ATTRIBUTE_NAME, 'G2Plot');
  66. };
  67. /**
  68. * 计算默认的 chart 大小。逻辑简化:如果存在 width 或 height,则直接使用,否则使用容器大小
  69. * @param width
  70. * @param height
  71. */
  72. Plot.prototype.getChartSize = function (width, height) {
  73. var chartSize = (0, utils_1.getContainerSize)(this.container);
  74. return { width: width || chartSize.width || 400, height: height || chartSize.height || 400 };
  75. };
  76. /**
  77. * 绑定代理所有 G2 的事件
  78. */
  79. Plot.prototype.bindEvents = function () {
  80. var _this = this;
  81. if (this.chart) {
  82. this.chart.on('*', function (e) {
  83. if (e === null || e === void 0 ? void 0 : e.type) {
  84. _this.emit(e.type, e);
  85. }
  86. });
  87. }
  88. };
  89. /**
  90. * 获取默认的 options 配置项
  91. * 每个组件都可以复写
  92. */
  93. Plot.prototype.getDefaultOptions = function () {
  94. return Plot.getDefaultOptions();
  95. };
  96. /**
  97. * 绘制
  98. */
  99. Plot.prototype.render = function () {
  100. // 暴力处理,先清空再渲染,需要 G2 层自行做好更新渲染
  101. this.chart.clear();
  102. // 因为子 view 会继承父 view 的 options 配置(包括 legend,所以会导致 legend 重复创建)
  103. // 所以这里给 chart 实例的 options 配置清空
  104. // 最好的解法是在 G2 view.clear 方法的时候,重置 options 配置。或者提供方法去 resetOptions
  105. // #1684 理论上在多 view 图形上,只要存在 custom legend,都存在类似问题(子弹图、双轴图)
  106. // @ts-ignore
  107. this.chart.options = {
  108. data: [],
  109. animate: true,
  110. };
  111. this.chart.views = []; // 删除已有的 views
  112. // 执行 adaptor
  113. this.execAdaptor();
  114. // 渲染
  115. this.chart.render();
  116. // 绑定
  117. this.bindSizeSensor();
  118. };
  119. /**
  120. * 更新: 更新配置且重新渲染
  121. * @param options
  122. */
  123. Plot.prototype.update = function (options) {
  124. this.updateOption(options);
  125. this.render();
  126. };
  127. /**
  128. * 更新配置
  129. * @param options
  130. */
  131. Plot.prototype.updateOption = function (options) {
  132. this.options = (0, utils_1.deepAssign)({}, this.options, options);
  133. };
  134. /**
  135. * 设置状态
  136. * @param type 状态类型,支持 'active' | 'inactive' | 'selected' 三种
  137. * @param conditions 条件,支持数组
  138. * @param status 是否激活,默认 true
  139. */
  140. Plot.prototype.setState = function (type, condition, status) {
  141. if (status === void 0) { status = true; }
  142. var elements = (0, utils_1.getAllElementsRecursively)(this.chart);
  143. (0, util_1.each)(elements, function (ele) {
  144. if (condition(ele.getData())) {
  145. ele.setState(type, status);
  146. }
  147. });
  148. };
  149. /**
  150. * 获取状态
  151. */
  152. Plot.prototype.getStates = function () {
  153. var elements = (0, utils_1.getAllElementsRecursively)(this.chart);
  154. var stateObjects = [];
  155. (0, util_1.each)(elements, function (element) {
  156. var data = element.getData();
  157. var states = element.getStates();
  158. (0, util_1.each)(states, function (state) {
  159. stateObjects.push({ data: data, state: state, geometry: element.geometry, element: element });
  160. });
  161. });
  162. return stateObjects;
  163. };
  164. /**
  165. * 更新数据
  166. * @override
  167. * @param options
  168. */
  169. Plot.prototype.changeData = function (data) {
  170. // @ts-ignore
  171. this.update({ data: data });
  172. // TODO: 临时方案,最好使用下面的方式去更新数据
  173. // this.chart.changeData(data);
  174. };
  175. /**
  176. * 修改画布大小
  177. * @param width
  178. * @param height
  179. */
  180. Plot.prototype.changeSize = function (width, height) {
  181. this.chart.changeSize(width, height);
  182. };
  183. /**
  184. * 增加图表标注。通过 id 标识,如果匹配到,就做更新
  185. */
  186. Plot.prototype.addAnnotations = function (annotations, view) {
  187. view = view ? view : this.chart;
  188. var incoming = tslib_1.__spreadArray([], annotations, true);
  189. var controller = view.getController('annotation');
  190. var current = controller.getComponents().map(function (co) { return co.extra; });
  191. controller.clear(true);
  192. var _loop_1 = function (i) {
  193. var annotation = current[i];
  194. var findIndex = incoming.findIndex(function (item) { return item.id && item.id === annotation.id; });
  195. if (findIndex !== -1) {
  196. annotation = (0, utils_1.deepAssign)({}, annotation, incoming[findIndex]);
  197. incoming.splice(findIndex, 1);
  198. }
  199. controller.annotation(annotation);
  200. };
  201. for (var i = 0; i < current.length; i++) {
  202. _loop_1(i);
  203. }
  204. incoming.forEach(function (annotation) { return controller.annotation(annotation); });
  205. view.render(true);
  206. };
  207. /**
  208. * 删除图表标注。通过 id 标识,如果匹配到,就做删除
  209. */
  210. Plot.prototype.removeAnnotations = function (annotations) {
  211. var controller = this.chart.getController('annotation');
  212. var current = controller.getComponents().map(function (co) { return co.extra; });
  213. controller.clear(true);
  214. var _loop_2 = function (i) {
  215. var annotation = current[i];
  216. if (!annotations.find(function (item) { return item.id && item.id === annotation.id; })) {
  217. controller.annotation(annotation);
  218. }
  219. };
  220. for (var i = 0; i < current.length; i++) {
  221. _loop_2(i);
  222. }
  223. this.chart.render(true);
  224. };
  225. /**
  226. * 销毁
  227. */
  228. Plot.prototype.destroy = function () {
  229. // 取消 size-sensor 的绑定
  230. this.unbindSizeSensor();
  231. // G2 的销毁
  232. this.chart.destroy();
  233. // 清空已经绑定的事件
  234. this.off();
  235. this.container.removeAttribute(SOURCE_ATTRIBUTE_NAME);
  236. };
  237. /**
  238. * 执行 adaptor 操作
  239. */
  240. Plot.prototype.execAdaptor = function () {
  241. var adaptor = this.getSchemaAdaptor();
  242. var _a = this.options, padding = _a.padding, appendPadding = _a.appendPadding;
  243. // 更新 padding
  244. this.chart.padding = padding;
  245. // 更新 appendPadding
  246. this.chart.appendPadding = appendPadding;
  247. // 转化成 G2 API
  248. adaptor({
  249. chart: this.chart,
  250. options: this.options,
  251. });
  252. };
  253. /**
  254. * 当图表容器大小变化的时候,执行的函数
  255. */
  256. Plot.prototype.triggerResize = function () {
  257. this.chart.forceFit();
  258. };
  259. /**
  260. * 绑定 dom 容器大小变化的事件
  261. */
  262. Plot.prototype.bindSizeSensor = function () {
  263. var _this = this;
  264. if (this.unbind) {
  265. return;
  266. }
  267. var _a = this.options.autoFit, autoFit = _a === void 0 ? true : _a;
  268. if (autoFit) {
  269. this.unbind = (0, size_sensor_1.bind)(this.container, function () {
  270. // 获取最新的宽高信息
  271. var _a = (0, utils_1.getContainerSize)(_this.container), width = _a.width, height = _a.height;
  272. // 主要是防止绑定的时候触发 resize 回调
  273. if (width !== _this.chart.width || height !== _this.chart.height) {
  274. _this.triggerResize();
  275. }
  276. });
  277. }
  278. };
  279. /**
  280. * 取消绑定
  281. */
  282. Plot.prototype.unbindSizeSensor = function () {
  283. if (this.unbind) {
  284. this.unbind();
  285. this.unbind = undefined;
  286. }
  287. };
  288. return Plot;
  289. }(event_emitter_1.default));
  290. exports.Plot = Plot;
  291. //# sourceMappingURL=plot.js.map