TypeScript 中的月相图形错误地呈现了盈亏相位

问题描述 投票:0回答:1

我正在开发一个 React/TypeScript 组件,它根据 0 到 1 之间的值渲染月相。问题是月相在第一季度和最后四分之一阶段之间无法正确渲染。具体来说,该组件将月亮显示为盈盈,而本应盈亏,反之亦然。

我尝试使用 Canvas 而不是 SVG,但没有解决问题。我还尝试将月球可见部分的计算更改为:

const visiblePortion = Math.cos(normalizedPhase * Math.PI * 2);

但问题并没有消失。在这些相位中,月亮的明/暗部分仍然是相反的,而不是在 0.25 和 0.75 之间正确渲染月亮。

0 到 1 刻度的月相

月相以 0 到 1 之间的数字表示,其中:

  • 0:新月(0%照明)
  • 0.125:打蜡新月(右侧约 25% 照明度)
  • 0.25:第一季度(右侧照明度为 50%)
  • 0.375:打蜡凸凸(右侧约 75% 照度)
  • 0.5:满月(100% 照明)
  • 0.625:渐亏凸月(左侧约 75% 照度)
  • 0.75:上季度(左侧照明度为 50%)
  • 0.875:渐亏新月(左侧约 25% 照度)
  • 1:新月(0% 照度)

我希望月亮在 0 到 0.5 之间逐渐盈,然后在 0.5 到 1 之间逐渐亏,但对于 0.25 到 0.75 之间的相位,明暗部分会交换。

当前代码

这是我正在使用的代码:

import React from "react";

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

const MoonPhase = ({
  phase,
  moonTexture = "/image/moon/moon.svg",
  rotation = 0,
}: MoonPhaseProps) => {
  // Ensure phase is between 0 and 1
  const normalizedPhase = Math.max(0, Math.min(phase, 1));

  console.log(phase, normalizedPhase);

  // Convert phase to radians
  const phaseRadians = normalizedPhase * 2 * Math.PI;

  // Determine if it's a waxing or waning phase
  const isWaxing = normalizedPhase <= 0.5;

  // Calculate the visible portion of the moon
  const visiblePortion = Math.cos(phaseRadians);

  // Adjust the path for waxing and waning phases
  const pathD = isWaxing
    ? `M50,0 A50,50 0 1,1 50,100 A${
        50 * Math.abs(visiblePortion)
      },50 0 1,0 50,0`
    : `M50,0 A50,50 0 1,0 50,100 A${
        50 * Math.abs(visiblePortion)
      },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="white" />
          <path d={pathD} fill="black" />
        </mask>
      </defs>

      {/* Moon texture */}
      <circle cx="50" cy="50" r="49" fill="url(#moonTexturePattern)" />

      {/* Shading for the dark side of the moon */}
      <circle
        cx="50"
        cy="50"
        r="49"
        fill="rgba(0,0,0,0.7)"
        mask="url(#moonMask)"
      />
    </svg>
  );
};

export default React.memo(MoonPhase);

提前致谢。

reactjs typescript math svg geometry
1个回答
0
投票

您希望月球的可见部分根据 cos(相位)规则从 0% 变化到 100%,但您未能检查角度转换中的端点是否有意义。您似乎想要:

cos(0) = 1, cos (pi/2) = 0, cos(pi) = -1

但是您可以将相位角(以弧度为单位)设置为乘以 2*pi :

 const visiblePortion = Math.cos(normalizedPhase * Math.PI * 2);

应该这样读

 const visiblePortion = Math.cos(normalizedPhase * Math.PI);

可见部分的符号决定隐藏哪一侧。

然后它应该要么正是你想要的,要么相反(在这种情况下是 s/cos/sin/)。

© www.soinside.com 2019 - 2024. All rights reserved.