最近工作中,完成了绘制图表功能,在这个过程中踩了一些坑,在这里分享给大家。
需求分析
接到需求后,开始进行需求分析,其他模块上已有完善的图表绘制功能,相关交互也有,因此,可行性是没问题的。在功能分析时,该功能内嵌3个子图表,每个图表有不同的绘制样式和叠加需求,可通过参数来控制差异,绘制流程是可复用的。
接下来分析现有绘制功能模块,发现现有实现考虑了众多绘制场景和特殊情况,针对本需求,有一些场景和情况是不会发生的,因此就有两种方案:
- 方案一: 在通用绘制模块中,添加控制参数和显示变量,来满足当前需求
- 方案二: 基于通用绘制模块,复制一份副本,在副本中,删除于当前需求无关的部分,并针对当前需求进行定制化
鉴于原先的绘制模块已经足够复杂,再增加控制变量,恐怕会对其他模块造成影响,因此,采用方案二。
定好方案后,然后结合需求和已有模块进行功能梳理,参考具体方案设计。
具体方案设计
通过梳理已有绘制模块的实现逻辑,主要要考虑以下几点:
- 数据预处理
- 图表坐标
- 图例
- 展示样式
- 副图
- 交互
下面分别来介绍。
数据预处理
数据预处理是针对后台返回的数据,进行预先处理,方便后续绘制。通过分析图表绘制逻辑,可将显示数据抽象为如下结构:
struct TChartData
{
public:
// 添加数据
void Add(unsigned int nDate, double data)
// 更新数据附加信息
void UpdateDataExInfo();
// 获得数据集中的最大、最小值
void GetMaxMin(double& dMax, double &dMin);
// 获得展示单位
string GetUnit();
private:
vector<unsigned int> m_vDate; // 日期
vector<double> m_vData; // 数据值
double m_dMaxValue; // 最大数
double m_dMinValue; // 最小数
double m_dUnit; // 展示单位
}
在上述结构中,日期采用 20211112
格式或者 134523
格式,分布表示日期或时间;数据采用 double
保存,整个数据集合按时间升序保存。
因为绘制需要,TChartData
提供 GetMaxMin
接口,同时对最大值进行向上取整、最小值进行向下取整。
为方便大数值展示,提供 m_dUnit
成员,方便图标坐标计算。
UpdateDataExInfo
函数实例如下:
void UpdateDataExInfo()
{
// .....
double dValue = max(abs(dMax), abs(dMin));
if (dValue > (10000.0 * 10000.0))
{
m_dUnit = (10000.0 * 10000.0); // 亿元
}
else if (dValue > (10000.0))
{
m_dUnit = (10000.0); // 万元
}
else
{
m_dUnit = (1.0); // 元
}
}
当有主、副图共同参与绘制时,还需要对主副图的数据进行对齐处理。此处需要产品确认绘制方案,主要考虑点:
- 对于某个序列有,另外没有时,如何处理?是留空、还是绘制特殊值?还是跳过不绘制?
图表坐标
通过前期数据预处理,绘制坐标就简单了,重点考虑以下几点:
- 坐标说明
- 垂直坐标的业务含义以及单位
- 水平坐标的均匀显示
- 坐标颜色显示
- 坐标背景的水平、垂直分割线
- 0轴坐标位置
这里,着重说明下0轴位置,因为它是后续绘制数据的基准。考虑到实际的数据分布,需要考虑如下三种情况:
- 数据全正:0轴位于图表最下方,0轴对应的数值为最小值
- 数据全负:0轴位于图表最上方。0轴对应的数值为最大值
- 数据有正有负:0轴位于图表中间,其距离图表顶部的距离计算公式为
总绘制高度*数据最大值/(数据最大值-数据最小值)
,0轴对应的数值为0.
图例
图例说明图表上不同颜色曲线的业务含义。为了便于区分,在柱状图的0轴上下,使用不同颜色绘制。主副图使用不同颜色绘制。
图例要与坐标的业务说明保持一致,具体位置可上可下,根据需求来定。
展示样式
常用的展示样式有:折线图、柱状图、K线图。一个图表模块,需要支持按某种样式来绘制,并且主图和副图可单独设置。
样式绘制注意:
-
折线图:为防止精度损失,要以浮点数来计算曲线点位置。点与点之间的距离根据总数量量和总绘制宽度来定,保证占满整个绘制区域。每单位数值对应的高度要提取算好。
-
柱状图:为优化显示,在显示区域内居中绘制,柱子宽度固定。考虑靠近0值的柱子方向,大于0和小于0使用不同颜色绘制,以示区分。
副图
绘制副图,除了和主图的坐标位置不一样外,其他均一样。
交互提示
图表交互提示主要以下几种,在设计时,需支持外部设置.
- 悬浮框提示:在鼠标当前位置展示提示框,在框内显示时间以及业务数据
- 坐标高亮块:在鼠标当前位置对应的X\Y轴上,以高亮显示当前位置的时间以及业务数据
小结
本文总结在绘制图表时的注意事项,包括数据预处理、图表坐标、图例、展示样式、副图以及交互,并重点介绍数据预处理的设计思路。
另外,在基于已有实现开发新需求时,不要被别人写的代码误导,也不要盲目在通用功能模块中添加支持。要权衡需求影响以及现有模块的复杂度,尽量减少新增功能对现有业务的影响。
在重写过程中,自己要有思考,不能盲目照搬原有实现,那么是无助于成长。