G2源码解析之函数式API与规范式API
背景
首先介绍两个定义:
图表画布:整个用于绘制图表内容的区域,包括图例、轴、以及图表名称。
图表数据映射区域:X
轴与Y
轴框定的,用于将柱子或者折线映射到像素的画布区域。
与ECharts
的Padding
仅解决图元向图表画布映射范围问题不同,G2
的Padding解决的不是图元布局问题而是真正意义上的图表数据映射区域到图表的边界的距离。
我们先来看G2
的解决方案:
G2
当图例、Y轴名称、Y轴标签或其余图元位置或大小发生变化时会挤占图表空间。
优点是:更加智能,且不会产生重叠,用户只需关心一个边距(Padding)的概念即可配置出相对好看的图表,更加易用。
缺点是:当出现极端数据例如10个数量级或者跟大的数值,或者极长的数据项名称时,图表的空间会被过度挤压以至于无法查看。
我们再来看ECharts
的解决方案:
ECharts
当图例、Y轴名称、Y轴标签或其余图元位置或大小发生变化时会不会挤占图表空间,不会更改数据到图表像素映射,如果图例过长一般会发生遮挡,如果轴标签过长则会产生覆盖。
优点:不会破坏图表的布局方式,在图表包含异常值时优先保证图表的正常显示。
缺点:不够智能,具有异常值时会产生遮挡或截断。
本文不讨论这两种实现方案哪种更优,仅尝试从源码的角度分析G2
是如何实现自适应映射范围的。
截图
G2截图来源于ChartCube - 在线图表制作工具 (alipay.com)
G2正面案例:当图例居左时
G2正面案例:当图例居下时
G2反面案例:当图例名称过长时
ECharts反面案例:图例位置单独布局
ECharts正面案例:虽然包含异常值,但图元和图例均有正常显示
简单实践
将chartcube的代码放到本地执行之后的效果
经简单测试发现对于图例的自适应应该是chartcube
层面实现的功能,这里不再讨论,仅聚焦于Y轴标签过长时的自适应方案
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
protected renderPaddingRecursive(isUpdate: boolean) { this.calculateViewBBox(); this.adjustCoordinate(); this.initComponents(isUpdate); this.autoPadding = calculatePadding(this).shrink(parsePadding(this.appendPadding)); this.coordinateBBox = this.viewBBox.shrink(this.autoPadding.getPadding()); this.adjustCoordinate();
const tooltipController = this.controllers.find((c) => c.name === 'tooltip'); tooltipController.update();
const views = this.views; for (let i = 0, len = views.length; i < len; i++) { const view = views[i]; view.renderPaddingRecursive(isUpdate); } }
public adjustCoordinate() { const { start: curStart, end: curEnd } = this.getCoordinate(); const start = this.coordinateBBox.bl; const end = this.coordinateBBox.tr;
if (isEqual(curStart, start) && isEqual(curEnd, end)) { this.isCoordinateChanged = false; return; } this.isCoordinateChanged = true; this.coordinateInstance = this.coordinateController.adjust(start, end); }
public adjust(start: Point, end: Point) { this.coordinate.update({ start, end, });
this.coordinate.resetMatrix(); this.execActions(['scale', 'rotate', 'translate']);
return this.coordinate; }
|
总结
简单梳理下G2
的布局逻辑:
首先给定图表的大小、比如宽高都为100,这个范围即为用于布局的坐标系范围。
之后会生成各个组件、例如X轴、Y轴。根据X轴的位置和Y轴的位置。在布局范围的外部(上下左右)添加坐标轴组件。
重新计算图表的真实大小(例如有一个在下方高为20的X轴现在图表的整体高度为120)。
重新计算出新的用于布局的坐标系范围并更新用于坐标计算的矩阵。
这种在布局范围之外添加组件之后反向更新布局范围的方式决定了其不会有重叠。