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

React Konva如何实现矩形围绕中心物体的旋转/公转动画

实现思路

  • 先计算中心矩形的中心点坐标:Konva 中 Rect 的 x/y 属性默认为左上角坐标,因此中心点为 中心Rect.x + 中心Rect.width/2、中心Rect.y + 中心Rect.height/2
  • 基于极坐标公式计算公转矩形的实时位置:以中心矩形的中心点为原点,根据当前旋转角度、公转轨道半径,换算为直角坐标系坐标,再减去公转矩形自身宽高的一半,保证公转矩形的中心点落在轨道上
  • 用 requestAnimationFrame 实现流畅的帧动画,每帧累加角度值触发重渲染,即可实现公转效果

完整实现代码

import { useState, useRef, useEffect } from 'react';
import { Stage, Layer, Rect } from 'react-konva';
// 这里的Button根据你项目用的UI库替换即可,原生的话直接用<button>
import { Button } from 'antd';

export default function OrbitDemo() {
  // 中心矩形的基础参数
  const centerRectConfig = {
    x: 20,
    y: 20,
    width: 50,
    height: 100,
    strokeWidth: 2,
    stroke: "red",
    fill: "blue"
  };
  // 公转矩形的基础参数
  const orbitRectConfig = {
    width: 50,
    height: 100,
    strokeWidth: 2,
    stroke: "black",
    fill: "black"
  };

  // 计算中心点坐标
  const centerX = centerRectConfig.x + centerRectConfig.width / 2;
  const centerY = centerRectConfig.y + centerRectConfig.height / 2;
  // 公转轨道半径,可自行调整
  const orbitRadius = 120;

  const [angle, setAngle] = useState(0);
  const [isRotating, setIsRotating] = useState(false);
  const animationRef = useRef(null);

  const handleRotate = () => {
    setIsRotating(prev => !prev);
  };

  useEffect(() => {
    if (isRotating) {
      const animate = () => {
        setAngle(prev => {
          // 每帧角度增量,数值越大公转速度越快,单位为弧度
          const newAngle = prev + 0.03;
          // 超过2π重置为0,避免数值过大
          return newAngle >= Math.PI * 2 ? 0 : newAngle;
        });
        animationRef.current = requestAnimationFrame(animate);
      };
      animationRef.current = requestAnimationFrame(animate);
    } else {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    }

    // 组件卸载时清除动画避免内存泄漏
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [isRotating]);

  // 计算公转矩形的实时位置
  const orbitX = centerX + orbitRadius * Math.cos(angle) - orbitRectConfig.width / 2;
  const orbitY = centerY + orbitRadius * Math.sin(angle) - orbitRectConfig.height / 2;

  // 可选:如果需要公转矩形自身也跟随旋转、始终朝向中心,给下面的Rect加上rotation属性:rotation={angle * 180 / Math.PI}

  return (
    <div>
      <Stage width={500} height={500}>
        <Layer>
          <Rect 
            {...centerRectConfig}
            opacity={1}         
          />
          <Rect 
            {...orbitRectConfig}
            x={orbitX}
            y={orbitY}
            opacity={1}         
          />
        </Layer>
      </Stage>
      <Button onClick={handleRotate}>{isRotating ? '暂停旋转' : '开始旋转'}</Button>
    </div>
  );
}

自定义调整说明

  • 修改orbitRadius的数值可以调整公转轨道的大小
  • 修改animate函数中newAngle = prev + 0.03的增量值可以调整公转速度,数值越大速度越快
  • 如果中心矩形位置会动态变化,只要更新centerRectConfig的x/y值,中心点会自动重新计算,公转轨道也会同步跟随

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 09:24:05