adaptor.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.adaptor = exports.slider = exports.legend = exports.limitInPlot = exports.animation = exports.theme = exports.annotation = exports.interaction = exports.tooltip = exports.axis = exports.meta = exports.color = exports.transformOptions = void 0;
  4. var tslib_1 = require("tslib");
  5. var util_1 = require("@antv/util");
  6. var common_1 = require("../../adaptor/common");
  7. var utils_1 = require("../../utils");
  8. var percent_1 = require("../../utils/transform/percent");
  9. var view_1 = require("../../utils/view");
  10. var constant_1 = require("./constant");
  11. var types_1 = require("./types");
  12. var geometry_1 = require("./util/geometry");
  13. var legend_1 = require("./util/legend");
  14. var option_1 = require("./util/option");
  15. var render_sider_1 = require("./util/render-sider");
  16. /**
  17. * transformOptions,双轴图整体的取参逻辑如下
  18. * 1. get index getOptions: 对应的是默认的图表参数,如 appendPadding,syncView 等
  19. * 2. get adpator transformOption: 对应的是双轴图的默认参数,deepAssign 优先级从低到高如下
  20. * 2.1 defaultoption,如 tooltip,legend
  21. * 2.2 用户填写 options
  22. * 2.3 根据用户填写的 options 补充的数组型 options,如 yaxis,GeometryOption,因为 deepAssign 无法 assign 数组
  23. *
  24. * @param params
  25. */
  26. function transformOptions(params) {
  27. var _a;
  28. var options = params.options;
  29. var _b = options.geometryOptions, geometryOptions = _b === void 0 ? [] : _b, xField = options.xField, yField = options.yField;
  30. var allLine = (0, util_1.every)(geometryOptions, function (_a) {
  31. var geometry = _a.geometry;
  32. return geometry === types_1.DualAxesGeometry.Line || geometry === undefined;
  33. });
  34. return (0, utils_1.deepAssign)({}, {
  35. options: {
  36. geometryOptions: [],
  37. meta: (_a = {},
  38. _a[xField] = {
  39. // 默认为 cat 类型
  40. type: 'cat',
  41. // x 轴一定是同步 scale 的
  42. sync: true,
  43. // 如果有没有柱子,则
  44. range: allLine ? [0, 1] : undefined,
  45. },
  46. _a),
  47. tooltip: {
  48. showMarkers: allLine,
  49. // 存在柱状图,不显示 crosshairs
  50. showCrosshairs: allLine,
  51. shared: true,
  52. crosshairs: {
  53. type: 'x',
  54. },
  55. },
  56. interactions: !allLine
  57. ? [{ type: 'legend-visible-filter' }, { type: 'active-region' }]
  58. : [{ type: 'legend-visible-filter' }],
  59. legend: {
  60. position: 'top-left',
  61. },
  62. },
  63. }, params, {
  64. options: {
  65. // yAxis
  66. yAxis: (0, option_1.transformObjectToArray)(yField, options.yAxis),
  67. // geometryOptions
  68. geometryOptions: [
  69. (0, option_1.getGeometryOption)(xField, yField[0], geometryOptions[0]),
  70. (0, option_1.getGeometryOption)(xField, yField[1], geometryOptions[1]),
  71. ],
  72. // annotations
  73. annotations: (0, option_1.transformObjectToArray)(yField, options.annotations),
  74. },
  75. });
  76. }
  77. exports.transformOptions = transformOptions;
  78. /**
  79. * 创建 双轴图 中绘制图形的 view,提前创建是因为 theme 适配器的需要
  80. * @param params
  81. */
  82. function createViews(params) {
  83. var _a, _b;
  84. var chart = params.chart, options = params.options;
  85. var geometryOptions = options.geometryOptions;
  86. var SORT_MAP = { line: 0, column: 1 };
  87. // 包含配置,id,数据的结构
  88. var geometries = [
  89. { type: (_a = geometryOptions[0]) === null || _a === void 0 ? void 0 : _a.geometry, id: constant_1.LEFT_AXES_VIEW },
  90. { type: (_b = geometryOptions[1]) === null || _b === void 0 ? void 0 : _b.geometry, id: constant_1.RIGHT_AXES_VIEW },
  91. ];
  92. // 将线的 view 放置在更上一层,防止线柱遮挡。先柱后先
  93. geometries.sort(function (a, b) { return -SORT_MAP[a.type] + SORT_MAP[b.type]; }).forEach(function (g) { return chart.createView({ id: g.id }); });
  94. return params;
  95. }
  96. /**
  97. * 绘制图形
  98. * @param params
  99. */
  100. function geometry(params) {
  101. var chart = params.chart, options = params.options;
  102. var xField = options.xField, yField = options.yField, geometryOptions = options.geometryOptions, data = options.data, tooltip = options.tooltip;
  103. // 包含配置,id,数据的结构
  104. var geometries = [
  105. tslib_1.__assign(tslib_1.__assign({}, geometryOptions[0]), { id: constant_1.LEFT_AXES_VIEW, data: data[0], yField: yField[0] }),
  106. tslib_1.__assign(tslib_1.__assign({}, geometryOptions[1]), { id: constant_1.RIGHT_AXES_VIEW, data: data[1], yField: yField[1] }),
  107. ];
  108. geometries.forEach(function (geometry) {
  109. var id = geometry.id, data = geometry.data, yField = geometry.yField;
  110. // 百分比柱状图需要额外处理一次数据
  111. var isPercent = (0, option_1.isColumn)(geometry) && geometry.isPercent;
  112. var formatData = isPercent ? (0, percent_1.percent)(data, yField, xField, yField) : data;
  113. var view = (0, view_1.findViewById)(chart, id).data(formatData);
  114. var tooltipOptions = isPercent
  115. ? tslib_1.__assign({ formatter: function (datum) { return ({
  116. name: datum[geometry.seriesField] || yField,
  117. value: (Number(datum[yField]) * 100).toFixed(2) + '%',
  118. }); } }, tooltip) : tooltip;
  119. // 绘制图形
  120. (0, geometry_1.drawSingleGeometry)({
  121. chart: view,
  122. options: {
  123. xField: xField,
  124. yField: yField,
  125. tooltip: tooltipOptions,
  126. geometryOption: geometry,
  127. },
  128. });
  129. });
  130. return params;
  131. }
  132. function color(params) {
  133. var _a;
  134. var chart = params.chart, options = params.options;
  135. var geometryOptions = options.geometryOptions;
  136. var themeColor = ((_a = chart.getTheme()) === null || _a === void 0 ? void 0 : _a.colors10) || [];
  137. var start = 0;
  138. /* 为 geometry 添加默认 color。
  139. * 1. 若 geometryOptions 存在 color,则在 drawGeometry 时已处理
  140. * 2. 若 不存在 color,获取 Geometry group scales个数,在 theme color 10 中提取
  141. * 3. 为防止 group 过多导致右色板无值或值很少,右 view 面板在依次提取剩下的 N 个 后再 concat 一次 themeColor
  142. * 4. 为简便获取 Geometry group scales个数,在绘制完后再执行 color
  143. * 5. 考虑之后将不同 view 使用同一个色板的需求沉淀到 g2
  144. */
  145. chart.once('beforepaint', function () {
  146. (0, util_1.each)(geometryOptions, function (geometryOption, index) {
  147. var view = (0, view_1.findViewById)(chart, index === 0 ? constant_1.LEFT_AXES_VIEW : constant_1.RIGHT_AXES_VIEW);
  148. if (geometryOption.color)
  149. return;
  150. var groupScale = view.getGroupScales();
  151. var count = (0, util_1.get)(groupScale, [0, 'values', 'length'], 1);
  152. var color = themeColor.slice(start, start + count).concat(index === 0 ? [] : themeColor);
  153. view.geometries.forEach(function (geometry) {
  154. if (geometryOption.seriesField) {
  155. geometry.color(geometryOption.seriesField, color);
  156. }
  157. else {
  158. geometry.color(color[0]);
  159. }
  160. });
  161. start += count;
  162. });
  163. chart.render(true);
  164. });
  165. return params;
  166. }
  167. exports.color = color;
  168. /**
  169. * meta 配置
  170. * @param params
  171. */
  172. function meta(params) {
  173. var _a, _b;
  174. var chart = params.chart, options = params.options;
  175. var xAxis = options.xAxis, yAxis = options.yAxis, xField = options.xField, yField = options.yField;
  176. (0, common_1.scale)((_a = {},
  177. _a[xField] = xAxis,
  178. _a[yField[0]] = yAxis[0],
  179. _a))((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW) }));
  180. (0, common_1.scale)((_b = {},
  181. _b[xField] = xAxis,
  182. _b[yField[1]] = yAxis[1],
  183. _b))((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW) }));
  184. return params;
  185. }
  186. exports.meta = meta;
  187. /**
  188. * axis 配置
  189. * @param params
  190. */
  191. function axis(params) {
  192. var chart = params.chart, options = params.options;
  193. var leftView = (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW);
  194. var rightView = (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW);
  195. var xField = options.xField, yField = options.yField, xAxis = options.xAxis, yAxis = options.yAxis;
  196. chart.axis(xField, false);
  197. chart.axis(yField[0], false);
  198. chart.axis(yField[1], false);
  199. // 左 View
  200. leftView.axis(xField, xAxis);
  201. leftView.axis(yField[0], (0, option_1.getYAxisWithDefault)(yAxis[0], types_1.AxisType.Left));
  202. // 右 Y 轴
  203. rightView.axis(xField, false);
  204. rightView.axis(yField[1], (0, option_1.getYAxisWithDefault)(yAxis[1], types_1.AxisType.Right));
  205. return params;
  206. }
  207. exports.axis = axis;
  208. /**
  209. * tooltip 配置
  210. * @param params
  211. */
  212. function tooltip(params) {
  213. var chart = params.chart, options = params.options;
  214. var tooltip = options.tooltip;
  215. var leftView = (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW);
  216. var rightView = (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW);
  217. // tooltip 经过 getDefaultOption 处理后,一定不为 undefined
  218. chart.tooltip(tooltip);
  219. // 在 view 上添加 tooltip,使得 shared 和 interaction active-region 起作用
  220. // view 应该继承 chart 里的 shared,但是从表现看来,继承有点问题
  221. leftView.tooltip({
  222. shared: true,
  223. });
  224. rightView.tooltip({
  225. shared: true,
  226. });
  227. return params;
  228. }
  229. exports.tooltip = tooltip;
  230. /**
  231. * interaction 配置
  232. * @param params
  233. */
  234. function interaction(params) {
  235. var chart = params.chart;
  236. (0, common_1.interaction)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW) }));
  237. (0, common_1.interaction)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW) }));
  238. return params;
  239. }
  240. exports.interaction = interaction;
  241. /**
  242. * annotation 配置
  243. * @param params
  244. */
  245. function annotation(params) {
  246. var chart = params.chart, options = params.options;
  247. var annotations = options.annotations;
  248. var a1 = (0, util_1.get)(annotations, [0]);
  249. var a2 = (0, util_1.get)(annotations, [1]);
  250. (0, common_1.annotation)(a1)((0, utils_1.deepAssign)({}, params, {
  251. chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW),
  252. options: {
  253. annotations: a1,
  254. },
  255. }));
  256. (0, common_1.annotation)(a2)((0, utils_1.deepAssign)({}, params, {
  257. chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW),
  258. options: {
  259. annotations: a2,
  260. },
  261. }));
  262. return params;
  263. }
  264. exports.annotation = annotation;
  265. function theme(params) {
  266. var chart = params.chart;
  267. /*
  268. * 双轴图中,部分组件是绘制在子 view 层(例如 axis,line),部分组件是绘制在 chart (例如 legend)
  269. * 为 chart 和 子 view 均注册 theme,使其自行遵循 G2 theme geometry > view > chart 进行渲染。
  270. */
  271. (0, common_1.theme)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW) }));
  272. (0, common_1.theme)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW) }));
  273. (0, common_1.theme)(params);
  274. return params;
  275. }
  276. exports.theme = theme;
  277. function animation(params) {
  278. var chart = params.chart;
  279. (0, common_1.animation)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW) }));
  280. (0, common_1.animation)((0, utils_1.deepAssign)({}, params, { chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW) }));
  281. return params;
  282. }
  283. exports.animation = animation;
  284. /**
  285. * 双轴图 limitInPlot
  286. * @param params
  287. */
  288. function limitInPlot(params) {
  289. var chart = params.chart, options = params.options;
  290. var yAxis = options.yAxis;
  291. (0, common_1.limitInPlot)((0, utils_1.deepAssign)({}, params, {
  292. chart: (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW),
  293. options: {
  294. yAxis: yAxis[0],
  295. },
  296. }));
  297. (0, common_1.limitInPlot)((0, utils_1.deepAssign)({}, params, {
  298. chart: (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW),
  299. options: {
  300. yAxis: yAxis[1],
  301. },
  302. }));
  303. return params;
  304. }
  305. exports.limitInPlot = limitInPlot;
  306. /**
  307. * legend 配置
  308. * 使用 custom,便于和类似于分组柱状图-单折线图的逻辑统一
  309. * @param params
  310. */
  311. function legend(params) {
  312. var chart = params.chart, options = params.options;
  313. var legend = options.legend, geometryOptions = options.geometryOptions, yField = options.yField, data = options.data;
  314. var leftView = (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW);
  315. var rightView = (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW);
  316. if (legend === false) {
  317. chart.legend(false);
  318. }
  319. else if ((0, util_1.isObject)(legend) && legend.custom === true) {
  320. chart.legend(legend);
  321. }
  322. else {
  323. var leftLegend_1 = (0, util_1.get)(geometryOptions, [0, 'legend'], legend);
  324. var rightLegend_1 = (0, util_1.get)(geometryOptions, [1, 'legend'], legend);
  325. // 均使用自定义图例
  326. chart.once('beforepaint', function () {
  327. var leftItems = data[0].length
  328. ? (0, legend_1.getViewLegendItems)({
  329. view: leftView,
  330. geometryOption: geometryOptions[0],
  331. yField: yField[0],
  332. legend: leftLegend_1,
  333. })
  334. : [];
  335. var rightItems = data[1].length
  336. ? (0, legend_1.getViewLegendItems)({
  337. view: rightView,
  338. geometryOption: geometryOptions[1],
  339. yField: yField[1],
  340. legend: rightLegend_1,
  341. })
  342. : [];
  343. chart.legend((0, utils_1.deepAssign)({}, legend, {
  344. custom: true,
  345. // todo 修改类型定义
  346. // @ts-ignore
  347. items: leftItems.concat(rightItems),
  348. }));
  349. });
  350. if (geometryOptions[0].seriesField) {
  351. leftView.legend(geometryOptions[0].seriesField, leftLegend_1);
  352. }
  353. if (geometryOptions[1].seriesField) {
  354. rightView.legend(geometryOptions[1].seriesField, rightLegend_1);
  355. }
  356. // 自定义图例交互
  357. chart.on('legend-item:click', function (evt) {
  358. var delegateObject = (0, util_1.get)(evt, 'gEvent.delegateObject', {});
  359. if (delegateObject && delegateObject.item) {
  360. var _a = delegateObject.item, field_1 = _a.value, isGeometry = _a.isGeometry, viewId = _a.viewId;
  361. // geometry 的时候,直接使用 view.changeVisible
  362. if (isGeometry) {
  363. var idx = (0, util_1.findIndex)(yField, function (yF) { return yF === field_1; });
  364. if (idx > -1) {
  365. var geometries = (0, util_1.get)((0, view_1.findViewById)(chart, viewId), 'geometries');
  366. (0, util_1.each)(geometries, function (g) {
  367. g.changeVisible(!delegateObject.item.unchecked);
  368. });
  369. }
  370. }
  371. else {
  372. var legendItem_1 = (0, util_1.get)(chart.getController('legend'), 'option.items', []);
  373. // 分组柱线图
  374. (0, util_1.each)(chart.views, function (view) {
  375. // 单折柱图
  376. var groupScale = view.getGroupScales();
  377. (0, util_1.each)(groupScale, function (scale) {
  378. if (scale.values && scale.values.indexOf(field_1) > -1) {
  379. view.filter(scale.field, function (value) {
  380. var curLegendItem = (0, util_1.find)(legendItem_1, function (item) { return item.value === value; });
  381. // 使用 legend 中的 unchecked 来判断,使得支持关闭多个图例
  382. return !curLegendItem.unchecked;
  383. });
  384. }
  385. });
  386. chart.render(true);
  387. });
  388. }
  389. }
  390. });
  391. }
  392. return params;
  393. }
  394. exports.legend = legend;
  395. /**
  396. * 双轴图 slider 适配器
  397. * @param params
  398. */
  399. function slider(params) {
  400. var chart = params.chart, options = params.options;
  401. var slider = options.slider;
  402. var leftView = (0, view_1.findViewById)(chart, constant_1.LEFT_AXES_VIEW);
  403. var rightView = (0, view_1.findViewById)(chart, constant_1.RIGHT_AXES_VIEW);
  404. if (slider) {
  405. // 左 View
  406. leftView.option('slider', slider);
  407. // 监听左侧 slider 改变事件, 同步右侧 View 视图
  408. leftView.on('slider:valuechanged', function (evt) {
  409. var _a = evt.event, value = _a.value, originValue = _a.originValue;
  410. if ((0, util_1.isEqual)(value, originValue)) {
  411. return;
  412. }
  413. (0, render_sider_1.doSliderFilter)(rightView, value);
  414. });
  415. chart.once('afterpaint', function () {
  416. // 初始化数据,配置默认值时需要同步
  417. if (!(0, util_1.isBoolean)(slider)) {
  418. var start = slider.start, end = slider.end;
  419. if (start || end) {
  420. (0, render_sider_1.doSliderFilter)(rightView, [start, end]);
  421. }
  422. }
  423. });
  424. }
  425. return params;
  426. }
  427. exports.slider = slider;
  428. /**
  429. * 双折线图适配器
  430. * @param chart
  431. * @param options
  432. */
  433. function adaptor(params) {
  434. // transformOptions 一定在最前面处理;color legend 使用了 beforepaint,为便于理解放在最后面
  435. return (0, utils_1.flow)(transformOptions, createViews,
  436. // 主题靠前设置,作为最低优先级
  437. theme, geometry, meta, axis, limitInPlot, tooltip, interaction, annotation, animation, color, legend, slider)(params);
  438. }
  439. exports.adaptor = adaptor;
  440. //# sourceMappingURL=adaptor.js.map