找回密码
 立即注册
首页 业界区 安全 React-Native开发鸿蒙NEXT-svg绘制睡眠质量图part2 ...

React-Native开发鸿蒙NEXT-svg绘制睡眠质量图part2

赵淳美 2025-5-30 13:44:52
React-Native开发鸿蒙NEXT-svg绘制睡眠质量图part2

FBI WARNING:
The complete demo will be posted at the end of the series<Rect
key={`connector-${areaData.areaIndex}`}
x={areaData.aeraX}
y={areaData.aeraY}
width={areaData.areaWidth}
height={areaData.areaHeight}
stroke={areaData.areaStoke}
fill={areaData.areaColor}
rx={5}
ry={5}
/>, so no need to worry.


上回进展到在画布上画出了睡眠采样点的数据,下面要做的是把同一阶段的相邻的点连接起来,让它具有形状。
先做个简单版的,类似excel那样用个方框连一连。
在svg中,可以用Rect来绘制一个矩形。基本的语法如下
  1.             <Rect
  2.               key={`connector-${areaData.areaIndex}`}
  3.               x={areaData.aeraX}
  4.               y={areaData.aeraY}
  5.               width={areaData.areaWidth}
  6.               height={areaData.areaHeight}
  7.             /><Rect
  8. key={`connector-${areaData.areaIndex}`}
  9. x={areaData.aeraX}
  10. y={areaData.aeraY}
  11. width={areaData.areaWidth}
  12. height={areaData.areaHeight}
  13. stroke={areaData.areaStoke}
  14. fill={areaData.areaColor}
  15. rx={5}
  16. ry={5}
  17. />,
复制代码
知道起点坐标加上宽高即可。首先创建一个areaData数组,用于记录矩形的绘制矩形的基本信息(暂时只要关注areaIndex<Rect
key={`connector-${areaData.areaIndex}`}
x={areaData.aeraX}
y={areaData.aeraY}
width={areaData.areaWidth}
height={areaData.areaHeight}
stroke={areaData.areaStoke}
fill={areaData.areaColor}
rx={5}
ry={5}
/>,areaX,areaY,areaWidth,areaHeight)
  1. interface SleepAreaData {
  2.   areaIndex: number; // 区域索引
  3.   aeraX: number; // 区域X坐标
  4.   aeraY: number; // 区域Y坐标
  5.   areaWidth: number; // 区域宽度
  6.   areaHeight: number; // 区域宽度
  7.   areaColor: any | null; // 区域颜色
  8.   areaStoke: any | null; // 区域阴影
  9.   areaLeftUpDown: UpDownEnum; // 区域左边上升下降趋势
  10.   areaRightUpDown: UpDownEnum; // 区域左边上升下降趋势
  11.   areaStage: number; // 睡眠阶段
  12.   areaBeginIndex: number; // 区域开始索引
  13.   areaEndIndex: number; // 区域结束索引
  14. }
复制代码
接着开始遍历画布上的数据点集合points,循环计算用于构建一个SleepAreaData数组,每计算出一个SleepAreaData对象,同时创建一个Rect对象。
  1.   const calcPointData = () => {    let areaData = initAreaData();    let svgsTemp: JSX.Element[] = [];    points.map((point<Rect
  2. key={`connector-${areaData.areaIndex}`}
  3. x={areaData.aeraX}
  4. y={areaData.aeraY}
  5. width={areaData.areaWidth}
  6. height={areaData.areaHeight}
  7. stroke={areaData.areaStoke}
  8. fill={areaData.areaColor}
  9. rx={5}
  10. ry={5}
  11. />, index) => {      if (index == 0) {        areaData.areaIndex = index;        areaData.aeraX = point.x;        areaData.aeraY = point.y;        areaData.areaWidth = 0;        areaData.areaColor = `url(#gradient${point.stage})`;        areaData.areaStoke = STAGE_CONFIG[point.stage].shadow;        areaData.areaLeftUpDown = UpDownEnum.UP;        areaData.areaStage = point.stage;        areaData.areaBeginIndex = index;      }      if (index - 1 >= 0) {        const prevPoint = points[index - 1];        const isSameStage = point.stage === prevPoint.stage;        areaData.areaWidth += point.x - prevPoint.x;        let deltaY1 = 0;        let deltaY2 = 0;        if (!isSameStage) {          if (point.stage > prevPoint.stage) {            deltaY1 = -AREA_HEIGHT;          } else {            deltaY2 = -AREA_HEIGHT;          }          areaData.areaEndIndex = index;          console.log('areaData.areaEndIndex = ' + index);          areaDataList.push(areaData);          // 输出          svgsTemp.push(            <Rect
  12.               key={`connector-${areaData.areaIndex}`}
  13.               x={areaData.aeraX}
  14.               y={areaData.aeraY}
  15.               width={areaData.areaWidth}
  16.               height={areaData.areaHeight}
  17.             /><Rect
  18. key={`connector-${areaData.areaIndex}`}
  19. x={areaData.aeraX}
  20. y={areaData.aeraY}
  21. width={areaData.areaWidth}
  22. height={areaData.areaHeight}
  23. stroke={areaData.areaStoke}
  24. fill={areaData.areaColor}
  25. rx={5}
  26. ry={5}
  27. />,          );          // 重新开始绘制矩形          areaData = initAreaData();          areaData.areaIndex = index;          areaData.aeraX = point.x;          areaData.aeraY = point.y;          areaData.areaWidth = 0;          areaData.areaColor = STAGE_CONFIG[point.stage].color;          areaData.areaStoke = STAGE_CONFIG[point.stage].shadow;          areaData.areaStage = point.stage;          areaData.areaBeginIndex = index;          if (point.stage > prevPoint.stage) {            areaData.areaLeftUpDown = UpDownEnum.UP;          } else {            areaData.areaLeftUpDown = UpDownEnum.DOWN;          }        }      }      if (index == points.length - 1) {        areaData.areaRightUpDown = UpDownEnum.DOWN;        areaData.areaEndIndex = index;        // 输出        areaDataList.push(areaData);        svgsTemp.push(            <Rect
  28.               key={`connector-${areaData.areaIndex}`}
  29.               x={areaData.aeraX}
  30.               y={areaData.aeraY}
  31.               width={areaData.areaWidth}
  32.               height={areaData.areaHeight}
  33.             /><Rect
  34. key={`connector-${areaData.areaIndex}`}
  35. x={areaData.aeraX}
  36. y={areaData.aeraY}
  37. width={areaData.areaWidth}
  38. height={areaData.areaHeight}
  39. stroke={areaData.areaStoke}
  40. fill={areaData.areaColor}
  41. rx={5}
  42. ry={5}
  43. />,        );      }    });    return svgsTemp;  };
复制代码
最终,这个方法向svg画布直接输出了一个Rect对象数组。
  1.       {/* 可视化图表 */}
  2.       <Svg height={CHART_HEIGHT + 80} width={SCREEN_WIDTH}>
  3.         ......
  4.         {/* 绘制 */}
  5.         {data.length > 1 && calcPointData()}
  6.         ......
  7.       </Svg>
复制代码
可以看到,相邻的阶段被用矩形连接了起来。

通过同时显示矩形和点,可以很直观地感受到上回说到的一个最重要的逻辑:

下一步的想法就是给这些方块做下圆角,上点颜色,再看看是否能做个渐变色,这样至少颜色上可以做到竞品的效果。这些Rect都支持
  1. <Rect
  2. key={`connector-${areaData.areaIndex}`}
  3. x={areaData.aeraX}
  4. y={areaData.aeraY}
  5. width={areaData.areaWidth}
  6. height={areaData.areaHeight}
  7. stroke={areaData.areaStoke}
  8. fill={areaData.areaColor}
  9. rx={5}
  10. ry={5}
  11. />,
复制代码

把上下相邻的两个阶段方块间加上虚线连接,线段的设置逻辑同样是在calcPointData中
  1. ......// 出一条线if (index != data.length - 1) {  svgsTemp.push(    <Rect
  2. key={`connector-${areaData.areaIndex}`}
  3. x={areaData.aeraX}
  4. y={areaData.aeraY}
  5. width={areaData.areaWidth}
  6. height={areaData.areaHeight}
  7. stroke={areaData.areaStoke}
  8. fill={areaData.areaColor}
  9. rx={5}
  10. ry={5}
  11. />,  );}// 重新开始绘制矩形areaData = initAreaData();areaData.areaIndex = index;areaData.aeraX = point.x;areaData.aeraY = point.y;areaData.areaWidth = 0;
复制代码
加上虚线连接,关掉数据点的显示后,此时的效果和网上为数不多的几个绘制睡眠图的开源库已经较为接近了

至此还剩下最后一步---把图上的矩形换成自定义的图形,根据不同阶段使用不同的图形样式。
To Be Continued...
不经常在线,有问题可在微信公众号或者掘金社区私信留言
更多内容可关注
我的公众号悬空八只脚

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册