注册
web

移动端的「基金地图」是怎么做的?


🙋🏻‍♀️ 编者按:本文作者是蚂蚁集团前端工程师芒僧,今年 8 月份开始到 9 月底,「支付宝 - 基金」里面的指数专区进行了一波大改版升级,这次借助 F2 4.0 强大的移动端手势交互能力,我们尝试了一种多维度探索式选基决策工具,本文具体介绍了它是如何实现的。



Kapture 2022-10-19 at 14.12.19.gif


这次在 「支付宝 - 基金」里的【指数专区改版】需求,我们玩了一种很新的东西 🌝


8月份开始到9月底,「支付宝 - 基金」里面的指数专区进行了一波大改版升级,这次借助 F2 4.0 强大的移动端手势交互能力,我们尝试了一种多维度探索式选基决策工具(如上动图所示)。


简单来说,用户可以在一个散点图上根据 「收益」和「波动」 这两个维度全览对比整个市场里的指数基金,并选出适合自己的指数基金进行投资,这个功能我们愿称其为 「指数图谱」 🐶 。



图谱是这个业务场景上的叫法,实际上图谱应该是关系图而非统计图.



image.pngimage.pngimage.png


功能已发布,页面访问路线如上


先看看有哪些功能点



  1. 精细打磨的移动端手势交互,平移、缩放、横扫不在话下 :

Simulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.00.49.gifSimulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.01.38.gifSimulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.43.17.gif


依次为:缩放、平移、横扫



  1. 底部产品卡和图表的联动交互:

Simulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.54.40.gifSimulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.54.40.gif


依次为:点击图表上的气泡、滑动底部卡片



  1. 无惧数据点太多看不到细节,我们有自适应的气泡抽样展示和自动聚焦:

Simulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 19.58.03.gifSimulator Screen Recording - iPhone 14 Pro Max - 2022-10-17 at 20.03.46.gif


依次为:抽样优化前、抽样优化后


那么,怎么做的呢?


最开始看到这个需求的时候,当时觉得可行性比较低。因为需求里面针对图谱的方案以及细节都特别模糊;不敢承诺各种功能和排期,所以先做了一轮比较完整的系分,增加一些说话的底气🫣


📱 第一步:同类产品调研


因为设计同学的灵感来自于 大众点评APP 上面的「美食地图」,所以第一步就是做了一次「同类产品调研」,仔细去看了一下 「美食地图」上究竟有哪些花样,有哪些体验优化的小细节,不看不知道,一看发现细节原来这么多啊 🤕:


图表和卡片的交互联动点抽样展示列表视图和卡片视图可切换交互时卡片自动折叠散点懒加载上滑直接唤起详情页
21.gif22.gif1658280205580-84108c85-793b-4318-89af-7504f3517613.gif24.gif25.gif1658280765505-5eb8bb05-30c5-45a0-bd81-9f494267b843.gif

做完这一步之后,大概能够知道自己距离“成品”有多远的距离,方便自己评估工期;另外还可以在系分评审的时候把这些细节提出来,防止临近发布了突然发现某个交互逻辑有个致命的漏洞(别问我怎么知道的,要命的)。
这波调研之后,最终我们在实现上致敬了「美食地图」50% 的体验细节优化 (狗头)。


⚙️ 第二步:功能点分析


第二步就是从需求本身的角度做功能点的分析,这样可以方便我们拆分组件,为后续做分层设计打下基础,明白哪些是需要支持可扩展的。这一步大家都熟悉,就不赘述了:
image.png


📦 第三步:通用化设计


有了功能点的分析之后,就可以进行通用化的设计了,这就来到了喜闻乐见的沉淀组件的设计环节 🌝


我们希望这个功能不仅仅是纯业务代码**,期望下次能够复用大部分核心功能 **(理想很丰满),所以在系分的时候是往通用化的方向去设计的,这里主要做了三件事情:分层设计概念标准化核心流程定义



  1. 分层设计

拆的逻辑是按最基础的 M(数据层) - C(控制层) - V(视图层) 拆分的。


image.png


有了分层设计和功能点分析之后,就可以知道哪些应该放到组件内,哪些接口应该被抽象成通用接口,哪些应该保留扩展性供使用者自己来定义,就可以画个表格了,一一决定哪些模块应该放到组件内:
image.png



  1. 概念标准化

下面来到造词环节,把一些常用的概念都定义成一个个名字,这样方便和后端、设计协同的时候效率更高,同时也方便自己定义清楚各个模型(类)。(这里其实取名越贴切越形象越好,有点考验语言能力了属实是)
image.png



  1. 核心流程定义

这一步是脑补环节,在脑子里跑一遍整体的流程,也是整个需求最核心的流程,比如这里会分成四种流程:初始化流程 、散点图交互流程、底部卡片交互流程、顶部tab交互流程


进而可以将四种流程里面的各节点做一些归类,比如都会有图表渲染、数据补全、卡片渲染这些共同的节点,而这些节点就可以实现成具体模型里的具体方法。


image.png


🌝 第四步:难点分析


根据上面拆分的各模块,列出哪些点是实现有困难的,耗时长的。这样就可以在评估工期的时候多 Battle 一下,还能砍砍需求,更可以让底层引擎/SDK来突破这些难点(比如找 F2 的核心开发者) :


image.png
image.png


📃 最后一步:


按照上述的设计进行代码编写。


难点实现


1. 移动端的图表手势交互体验优化


开发之初,F2 只支持单轴(x或者y)的平移缩放,也不支持全方向交互;在 swipe 上的体验也不太好(阻尼感很强),所以在项目开发过程中, F2 完成了很多体验优化,打磨出很多细致入微的良好体验:



  • X轴、Y轴可同时开启平移、缩放
  • swiper 体验效果优化
  • 移出可视区之后的蒙层遮挡能力(view-clip)
  • zIndex 元素层叠渲染
  • 平移缩放性能优化

2. 气泡抽样展示优化


因为散点图上的点在初始化的缩放比例下分布非常密集,所以如果每个点上面都绘制一个气泡的话,就会显得密密麻麻的,根本无从下手(如下图1所示)。针对这样的问题,做了「气泡抽样展示」的优化。


image.png


实现方式上就是渲染前遍历所有的点,如果在这个点周围某个半径距离之内有其他点,那么就认为这个点是脏点(dirty point),最后筛选出所有“干净”的点进行气泡展示。


如下图图1所示,灰色点(右上角)是干净点,而灰白色的点(偏中间的位置)因为其在圆圈半径范围之内有其他点存在,所以这个点是脏点。


image.png



多提一句,这样的过滤方式会使得密集区域的点都不会展示气泡,后续会进行优化。



3. 获取到可视区内的所有点


image.png
由于做了气泡抽样展示,所以上图中的底部卡片只会展示用户可视区内散点图上有气泡的点(细心的盆友可以发现,散点图上有两种点,一种是带气泡的交互点,一种是不带气泡的缩略点)。那么就需要一个获取「可视区内所有的点」,实现思路如下:


- 监听 PanEnd(平移结束)、PinchEnd(缩放结束), SwipeEnd(横扫结束)的事件
- 获取到平移/缩放/横扫之后最新的 scales
- 根据最新的 scales 里面的 x、y 的 range 过滤一遍图表原数据
- 将脏点从上一步的结果过滤出去
- 底部卡片根据上一步的结果进行渲染展示
- 结束



// 根据当前的缩放比例,拿到「可视区」范围内的数据
function getRecordsByZoomScales(scales, data) {
const { x: xScale, y: yScale } = scales;
const { field: xField, min: xMin, max: xMax } = xScale;
const { field: yField, min: yMin, max: yMax } = yScale;

return data.filter((record) => {
const isInView =
record[xField] >= xMin &&
record[xField] <= xMax &&
record[yField] >= yMin &&
record[yField] <= yMax;

return isInView;
});
}


// 使用时
export default props => {
// 图表原数据
const { data } = props;

function handlePanEnd (scales, data) {
// 手动高亮下面这一行
getRecordsByZoomScales(scales, data);
}

return (
<ReactCanvas>
<Chart>
{/* ... */}
<ScrollBar onPanEnd={handlePanEnd}/>
</Chart>
</ReactCanvas>

)

}

4. 数据懒加载


image.pngimage.png
底部卡片的数量是由散点图上点的数量决定的,而每张卡上都有不少的数据量(基金产品信息、指数信息、标签信息),所以不能一次性就把所有点里关联的数据都查询出来(会导致接口返回数据过多)。


这里采取的是懒加载的方式 ,每次只在交互后查询相邻 N+2/N-2 张的卡片数据,并且增加了一份内存缓存来存储已经查询过的卡片数据:


image.png


基本的流程图如下:


- 触发散点图交互/滑动底部卡片
- 读取缓存,过滤出没有缓存过的卡片
- 发起数据调用,获取到卡片的数据
- 写入缓存
- 更新卡片数据,返回
- 更新卡片视图,渲染完成

实际线上效果


项目上线之后,我们发现散点图区域的交互率(包含平移,缩放)非常高,可以看出用户对新类型的选基工具抱有新鲜感,也乐于去进行探索;也有部分用户能够通过工具完成决策或者进行产品之间的详细对比(即点击底部卡片上的详情按钮),起到了一个工具类产品的作用 🌝 。


致谢


感谢 AntV 以及 F2 对移动端图表交互能力的支持。


作者:支付宝体验科技
来源:juejin.cn/post/7176891015112949819

0 个评论

要回复文章请先登录注册