基于原生canvas的多平台股票线图组件框架

453 阅读8分钟

0 现状

目前有很多基于H5技术的优秀图表库,例如TradingView、echart等,在浏览器上实现了强大的绘制能力和渲染速度,以及最重要的跨平台性。然而无论如何优化,H5图表在大量数据刷新和复杂图形渲染、原生事件响应上,难以达到原生的性能效果。

考察原生系统上的图表库,由于系统种类繁多,各个平台上独立的图表库都难以支持多个平台。且不同的设计目标和理念,导致图表库框架差异极大,学习和适配成本极大。

因此,需要一种图表框架,能够提供一种统一的设计理念,并达到框架层面的统一,从而可以实现在不同原生系统上快速的迁移,减少学习和开发成本。

1 解决方案

为了解决上述问题,一方面满足高性能要求,实现更好的事件响应,另一方面减少原生多平台的迁移和学习成本,现在提出一种图表框架HChart。

HChart是一个基于canvas绘制机制的多平台原生股票图表框架。提供高性能的、易于功能扩展和定制化的、跨平台的证券可视化图表绘制框架。目前已提供基于flutter的跨平台组件库,也提供iOS、鸿蒙原生实现组件库。同时作为基于canvas的绘制框架,易于迁移到其他原生系统平台。

2 功能预览

下面以 flutter 上的 hchart_flutter 为例, 当前支持功能:

  • K线图(蜡烛图、线图)
    • 拖动
    • 缩放(桌面端上下滑动事件控制、移动端亦可支持两指操作)
  • 副图指标。默认支持(算法可自行调整):
    • vol
    • macd
    • kdj
  • 多副图指标(最大4个)
  • 查价线(十字线)
    • 闪烁点
  • 现价线,点击滑到最新
  • 趋势线(包含渐变阴影)

flutter版预览如下:

iOS版预览如下:

3 框架分析

3.1 基于Canvas绘图机制

原生系统提供了基于自身技术栈的UI绘制机制。无论是从高级语言层面,还是底层绘制框架方面,都差距甚远。这造成了很多优秀的图表组件,只能在单独原生系统上应用。

狭义上的Canvas通常指的是HTML5 Canvas技术,但各个主流原生系统都提供了类似标准的实现,例如iOS 和 macOS 的 Core Graphics、Android 的 Canvas 类、Windows 平台有 Direct2D 和 WPF 中的 DrawingContext等。

因此采用基于canvas绘制方式,可以在各个平台的渲染层取得较好的统一效果。

HChart基于canvas绘制机制,实现图表底层绘制。将不同系统的canvas api,统一封装到painting层,实现与特定系统解耦的物理图形绘制层。

3.2 统一的分层架构

HChart 基于统一的分层架构,即便底层原生系统不同,基于系统的上层架构保持统一。

3.2.1 整体架构

整体架构图如下:

Platform

Platform为系统层。在设计上,HChart 支持移动端(iOS、Android、HarmonyOS)和桌面端(macOS、Windows、Linux)等提供类Canvas绘图机制的原生系统。虽然底层系统不同,系统开发语言不同,但基本上都会提供类似Canvas Api 风格的绘图机制。HChart将基于类似的Canvas Api,完成上层图表库构建。

HChart

HChart 总体上分为三层架构:

  • Painting 层为物理图形绘制层。基于类Canvas Api,Painting层封装基础物理图形Model,并提供统一的绘制机制(基于panel和painter),实现基础图形(line、rect、point等)的绘制。
  • Rendering 层为节点渲染层。图表可以分拆为坐标系、折线、查价线等有一定业务意义的通用node,rendering层对这些通用node进行绘制渲染,供上层进行组合拼装。
  • views 和 data model 为组件接口层。将提供对外的图表组件,供业务上层使用。
    • views 提供股票线图中经常使用的图表组件,例如K线图、分时图等。这些图表组件按照一定的业务意义,通过将rendering层的node进行组合,并实现系统本身事件(滑动、点击等)的交互。
    • data model 为对外数据Model,业务上层将业务数据转化和打包,按照dataset的格式传给views图表组件。

3.2.2 HChart 架构

HChart 架构图:

HChart总体分为自下而上依赖的三层结构。上文已有介绍,具体来说:

  • Painting 物理图形绘制层:
    • Panel 为Canvas绘制画板。基于原生系统上的Canvas Api,提供封装的绘制区域类。
    • Painter 为适配原生系统的绘制方法。
    • Graphic Foundation 为统一的基础物理图形类。HChart 自定义一套基本图形,不直接依赖原生系统提供的基础图形Model。
  • Rendering 节点渲染层:
    • Renderer 为基础图元渲染器。提供Line(折线)、Rect(蜡烛图)等基础图元的渲染实现。渲染时需按照特定协议(provider)进行数据处理,转化为可渲染的UI数据Model。
    • Node 为基础业务图形节点。这些节点按照业务要求,通过对数据处理,使用Renderer进行渲染,提供基础的股票线图。包含线图坐标、K线、查价线等股票线图上常见的节点类型。
  • View 组件接口层:
    • View 为对外提供的图表组件。图表组件组合各个图形node,提供符合业务要求的股票图表。为满足丰富的交互要求,图表组件会直接使用符合原生系统交互机制进行事件处理,例如滑动、点击、缩放等效果。
    • Config 为图表组件配置器。可通过config对图表控件的展示效果和功能进行控制。
    • Data Model 为图表数据类。上层业务数据需按照HChart要求,进行数据处理和转化,并打包传入图表组件。

3.2.3 UML类图

HChart 在不同平台都有实现,遵从相似的框架设计。以下提供UML类(参照HarmonyOS版本HChart)图供参考:

  1. View和Data Model 向外提供
    1. View: 线图UI类,提供包含交互事件处理的线图UI。
    2. Data Model: 数据类,业务上层需要按Data Model处理数据并传入。
  1. ChartNode: 线图UI节点,如线图节点(LineNode),指标图节点(TecNode)。通过组合方式加入View。
  2. Renderer: 节点渲染类,包含对axis、line等节点图形的绘制。
  3. DataProvider: 渲染数据接口。ChartNode需实现该接口,为Renderer提供可以渲染的UI数据。
  4. ChartComponent: UI数据类。封装的点、线等UI数据Model。

3.3 通用的接口设计

HChart 遵从统一的对外接口设计。具体体现在View 和 DataModel。

  • View 提供基础股票线图,支持点击、滑动、缩放等基础交互功能。
  • DataModel 要求统一的数据封装方法。分为:
    • ChartDataEntry 为基础数据Model。按业务划分为point、kline等,包含有特定业务意义的字段。上层业务数据需转化为ChartDataEntry。
    • ChartDataSet 为数据集合,按股票图表的业务类别可分为不同类型。
    • HFChartData 为最终传入图表组件的数据格式。

3.4 支持扩展的组合方式

HChart 的核心绘制主要在Rendering层。Rendering层以Node方式提供较为通用的业务图形节点。因此:

  • 上层View可以灵活的采取组合的方式,合理的组合各种Node,实现自定义线图。
  • 上层View更多的关注原生系统的事件处理,使得组件拥有更适配平台特性的交互效果。

除此之外,当提供的通用Node不满足业务需求时,亦可通过扩展Node和Renderer的方式,实现更多的线图绘制方式。

4 结论

HChart作为一个跨平台图表框架,通过提供一套完整的框架建设思想,方便地迁移到任何提供类Canvas绘图机制的原生平台。

HChart目前已支持多个平台,包括iOS、HarmonyOS和Flutter。

其中iOS端是最早支持的原生系统,是HChart框架思想最早探索的阶段。由于实现较早,更多的与单个原生系统强绑定。

HarmonyOS即鸿蒙系统版本,是基于全新的arkts和stage模型实现的一套股票线图库。是HChart框架迁移到具体原生平台的一次尝试,从迁移效率和实现效果取得了较好的预期效果。

flutter版本较好的体现HChart的框架设计思想。由于flutter本身的跨平台特性,且基于skia得到了较好的原生性能体验,使得HChart即便在未开展优化的情况下,在移动端特别是桌面端上也都取得较好的效果。

当然如果追求更卓越的原生性能体验,也可以将HChart方便的迁移到更多的原生平台。HChart的代码库可供开发者参考和使用:

flutter:gitee.com/hotacool/hc…

iOS:gitee.com/hotacool/HS…

HarmonyOS:gitee.com/hotacool/ha…