You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript月相组件:渐盈与渐亏阶段渲染错误问题

解决月相渲染颠倒问题

问题根源在于遮罩逻辑与相位计算的双重颠倒:

  1. 原mask的黑白填充逻辑搞反了,导致阴影显示区域与预期相反
  2. visiblePortion的计算方式错误,无法正确对应渐盈/渐亏阶段的暗部范围

关键修改点

  1. 修正遮罩逻辑:将mask默认填充改为黑色(禁止阴影显示),path填充改为白色(允许阴影显示暗部)
  2. 重新计算暗部宽度:根据相位区间生成对应的暗部比例,0-0.5区间暗部从全圆缩小到消失,0.5-1区间暗部从0扩展到全圆
  3. 调整路径方向:渐盈阶段绘制左侧暗部路径,渐亏阶段绘制右侧暗部路径

修改后的完整代码

import React from "react";

interface MoonPhaseProps {
  phase: number;
  moonTexture?: string;
  rotation?: number;
}

const MoonPhase = ({
  phase,
  moonTexture = "/image/moon/moon.svg",
  rotation = 0,
}: MoonPhaseProps) => {
  // 确保相位在0-1范围内
  const normalizedPhase = Math.max(0, Math.min(phase, 1));

  // 计算暗部的宽度比例:0-0.5从1到0,0.5-1从0到1
  const visiblePortion = normalizedPhase <= 0.5 
    ? 1 - 2 * normalizedPhase 
    : 2 * (normalizedPhase - 0.5);

  const rx = 50 * visiblePortion;

  // 生成对应相位的路径:渐盈(左暗)/渐亏(右暗)
  const pathD = normalizedPhase <= 0.5
    ? `M50,0 A${rx},50 0 1,1 50,100 A${rx},50 0 1,0 50,0`
    : `M50,0 A${rx},50 0 1,0 50,100 A${rx},50 0 1,1 50,0`;

  return (
    <svg
      width="100%"
      viewBox="0 0 100 100"
      data-phase={phase}
      style={{
        transform: `rotate(${rotation}deg)`,
        transition: "transform 0.3s ease-in-out",
      }}
    >
      <defs>
        <pattern
          id="moonTexturePattern"
          patternUnits="userSpaceOnUse"
          width="100"
          height="100"
        >
          <image href={moonTexture} x="0" y="0" width="100" height="100" />
        </pattern>

        <mask id="moonMask">
          {/* 默认禁止阴影显示(亮部) */}
          <rect x="0" y="0" width="100" height="100" fill="black" />
          {/* 允许阴影显示的区域(暗部) */}
          <path d={pathD} fill="white" />
        </mask>
      </defs>

      {/* 月亮纹理 */}
      <circle cx="50" cy="50" r="49" fill="url(#moonTexturePattern)" />

      {/* 暗部阴影 */}
      <circle
        cx="50"
        cy="50"
        r="49"
        fill="rgba(0,0,0,0.7)"
        mask="url(#moonMask)"
      />
    </svg>
  );
};

export default React.memo(MoonPhase);

验证对应关系

  • 0/1:新月(全暗,阴影覆盖整个月亮)
  • 0.125:渐盈蛾眉月(右侧25%亮,左侧75%暗)
  • 0.25:上弦月(右侧50%亮,左侧50%暗)
  • 0.375:渐盈凸月(右侧75%亮,左侧25%暗)
  • 0.5:满月(全亮,无阴影)
  • 0.625:渐亏凸月(左侧75%亮,右侧25%暗)
  • 0.75:下弦月(左侧50%亮,右侧50%暗)
  • 0.875:渐亏残月(左侧25%亮,右侧75%暗)

内容的提问来源于stack exchange,提问作者Best Codes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:35:58