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

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

FBI WARNING:
The complete demo will be posted at the end of the series, so no need to worry.

上回进展到在画布上画出了睡眠采样点的数据,下面要做的是把同一阶段的相邻的点连接起来,让它具有形状。

先做个简单版的,类似excel那样用个方框连一连。

在svg中,可以用Rect来绘制一个矩形。基本的语法如下

typescript 复制代码
            <Rect
              key={`connector-${areaData.areaIndex}`}
              x={areaData.aeraX}
              y={areaData.aeraY}
              width={areaData.areaWidth}
              height={areaData.areaHeight}
            />,

知道起点坐标加上宽高即可。首先创建一个areaData数组,用于记录矩形的绘制矩形的基本信息(暂时只要关注areaIndex,areaX,areaY,areaWidth,areaHeight)

typescript 复制代码
interface SleepAreaData {
  areaIndex: number; // 区域索引
  aeraX: number; // 区域X坐标
  aeraY: number; // 区域Y坐标
  areaWidth: number; // 区域宽度
  areaHeight: number; // 区域宽度
  areaColor: any | null; // 区域颜色
  areaStoke: any | null; // 区域阴影
  areaLeftUpDown: UpDownEnum; // 区域左边上升下降趋势
  areaRightUpDown: UpDownEnum; // 区域左边上升下降趋势
  areaStage: number; // 睡眠阶段
  areaBeginIndex: number; // 区域开始索引
  areaEndIndex: number; // 区域结束索引
}

接着开始遍历画布上的数据点集合points,循环计算用于构建一个SleepAreaData数组,每计算出一个SleepAreaData对象,同时创建一个Rect对象。

typescript 复制代码
  const calcPointData = () => {
    let areaData = initAreaData();
    let svgsTemp: JSX.Element[] = [];
    points.map((point, 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
              key={`connector-${areaData.areaIndex}`}
              x={areaData.aeraX}
              y={areaData.aeraY}
              width={areaData.areaWidth}
              height={areaData.areaHeight}
            />,
          );
          // 重新开始绘制矩形
          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
              key={`connector-${areaData.areaIndex}`}
              x={areaData.aeraX}
              y={areaData.aeraY}
              width={areaData.areaWidth}
              height={areaData.areaHeight}
            />,
        );
      }
    });
    return svgsTemp;
  };

最终,这个方法向svg画布直接输出了一个Rect对象数组。

typescript 复制代码
      {/* 可视化图表 */}
      <Svg height={CHART_HEIGHT + 80} width={SCREEN_WIDTH}>
        ......
        {/* 绘制 */}
        {data.length > 1 && calcPointData()}
        ......
      </Svg>

可以看到,相邻的阶段被用矩形连接了起来。

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

下一步的想法就是给这些方块做下圆角,上点颜色,再看看是否能做个渐变色,这样至少颜色上可以做到竞品的效果。这些Rect都支持

typescript 复制代码
<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}
/>,

把上下相邻的两个阶段方块间加上虚线连接,线段的设置逻辑同样是在calcPointData中

typescript 复制代码
......
// 出一条线
if (index != data.length - 1) {
  svgsTemp.push(
    <Line
      key={`line-${index}`}
      x1={point.x}
      y1={point.y - deltaY1}
      x2={point.x}
      y2={areaData.aeraY - deltaY2}
      stroke="#999"
      strokeWidth="1"
      strokeDasharray="4 2"
    />,
  );
}
// 重新开始绘制矩形
areaData = initAreaData();
areaData.areaIndex = index;
areaData.aeraX = point.x;
areaData.aeraY = point.y;
areaData.areaWidth = 0;

加上虚线连接,关掉数据点的显示后,此时的效果和网上为数不多的几个绘制睡眠图的开源库已经较为接近了

至此还剩下最后一步---把图上的矩形换成自定义的图形,根据不同阶段使用不同的图形样式。

To Be Continued...


不经常在线,有问题可在微信公众号或者掘金社区私信留言

更多内容可关注

我的公众号悬空八只脚

相关推荐
我爱鸿蒙开发15 分钟前
🥇聊聊鸿蒙的一端开发,多端部署。
前端·开源·harmonyos
智驾3 小时前
HarmonyOS 是 Android 套壳嘛?
android·harmonyos·替代·套壳
鸿蒙开发工程师—阿辉5 小时前
HarmonyOS Next 编译之如何使用多目标产物不同包名应用
华为·harmonyos
fei_sun15 小时前
【HarmonyOS】ArKUI框架
华为·harmonyos
鸿蒙布道师16 小时前
鸿蒙NEXT开发权限工具类(申请授权相关)(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师16 小时前
鸿蒙NEXT开发定位工具类 (WGS-84坐标系)(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
万叶学编程16 小时前
鸿蒙移动应用开发--渲染控制实验
前端·华为·harmonyos
别说我什么都不会20 小时前
【仓颉三方库】对象存储——OBS Cangjie SDK
harmonyos
星释21 小时前
鸿蒙Flutter仓库停止更新?
flutter·华为·harmonyos