• 图表绘制小结


    最近工作中,完成了绘制图表功能,在这个过程中踩了一些坑,在这里分享给大家。

    需求分析

    接到需求后,开始进行需求分析,其他模块上已有完善的图表绘制功能,相关交互也有,因此,可行性是没问题的。在功能分析时,该功能内嵌3个子图表,每个图表有不同的绘制样式和叠加需求,可通过参数来控制差异,绘制流程是可复用的。

    接下来分析现有绘制功能模块,发现现有实现考虑了众多绘制场景和特殊情况,针对本需求,有一些场景和情况是不会发生的,因此就有两种方案:

    • 方案一: 在通用绘制模块中,添加控制参数和显示变量,来满足当前需求
    • 方案二: 基于通用绘制模块,复制一份副本,在副本中,删除于当前需求无关的部分,并针对当前需求进行定制化

    鉴于原先的绘制模块已经足够复杂,再增加控制变量,恐怕会对其他模块造成影响,因此,采用方案二。

    定好方案后,然后结合需求和已有模块进行功能梳理,参考具体方案设计。

    具体方案设计

    通过梳理已有绘制模块的实现逻辑,主要要考虑以下几点:

    1. 数据预处理
    2. 图表坐标
    3. 图例
    4. 展示样式
    5. 副图
    6. 交互

    下面分别来介绍。

    数据预处理

    数据预处理是针对后台返回的数据,进行预先处理,方便后续绘制。通过分析图表绘制逻辑,可将显示数据抽象为如下结构:

    
    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);			    // 元
    	}
    	
    }
    
    

    当有主、副图共同参与绘制时,还需要对主副图的数据进行对齐处理。此处需要产品确认绘制方案,主要考虑点:

    1. 对于某个序列有,另外没有时,如何处理?是留空、还是绘制特殊值?还是跳过不绘制?

    图表坐标

    通过前期数据预处理,绘制坐标就简单了,重点考虑以下几点:

    • 坐标说明
      • 垂直坐标的业务含义以及单位
      • 水平坐标的均匀显示
      • 坐标颜色显示
    • 坐标背景的水平、垂直分割线
    • 0轴坐标位置

    这里,着重说明下0轴位置,因为它是后续绘制数据的基准。考虑到实际的数据分布,需要考虑如下三种情况:

    • 数据全正:0轴位于图表最下方,0轴对应的数值为最小值
    • 数据全负:0轴位于图表最上方。0轴对应的数值为最大值
    • 数据有正有负:0轴位于图表中间,其距离图表顶部的距离计算公式为 总绘制高度*数据最大值/(数据最大值-数据最小值) ,0轴对应的数值为0.

    图例

    图例说明图表上不同颜色曲线的业务含义。为了便于区分,在柱状图的0轴上下,使用不同颜色绘制。主副图使用不同颜色绘制。

    图例要与坐标的业务说明保持一致,具体位置可上可下,根据需求来定。

    展示样式

    常用的展示样式有:折线图、柱状图、K线图。一个图表模块,需要支持按某种样式来绘制,并且主图和副图可单独设置。

    样式绘制注意:

    • 折线图:为防止精度损失,要以浮点数来计算曲线点位置。点与点之间的距离根据总数量量和总绘制宽度来定,保证占满整个绘制区域。每单位数值对应的高度要提取算好。

    • 柱状图:为优化显示,在显示区域内居中绘制,柱子宽度固定。考虑靠近0值的柱子方向,大于0和小于0使用不同颜色绘制,以示区分。

    副图

    绘制副图,除了和主图的坐标位置不一样外,其他均一样。

    交互提示

    图表交互提示主要以下几种,在设计时,需支持外部设置.

    1. 悬浮框提示:在鼠标当前位置展示提示框,在框内显示时间以及业务数据
    2. 坐标高亮块:在鼠标当前位置对应的X\Y轴上,以高亮显示当前位置的时间以及业务数据

    小结

    本文总结在绘制图表时的注意事项,包括数据预处理、图表坐标、图例、展示样式、副图以及交互,并重点介绍数据预处理的设计思路。

    另外,在基于已有实现开发新需求时,不要被别人写的代码误导,也不要盲目在通用功能模块中添加支持。要权衡需求影响以及现有模块的复杂度,尽量减少新增功能对现有业务的影响。

    在重写过程中,自己要有思考,不能盲目照搬原有实现,那么是无助于成长。

  • 相关阅读:
    DockerPush
    DockerInstall
    DockerFile
    基于虚拟机实例/java程序线程的虚拟机内存分配
    Class文件结构及方法中的指令
    JAVA类型生命周期的开始阶段和使用阶段/以及创建对象的几种方式
    。。。。。毕业季
    PCA算法
    ffmpeg将图片转为视频
    Linux下使用bgslibrary的OpenCv库
  • 原文地址:https://www.cnblogs.com/cherishui/p/16075954.html
Copyright © 2020-2023  润新知