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

拖拽边角绕中心旋转非正方形矩形的异常问题咨询

修复非正方形矩形旋转时的跳转问题

问题根源

你的代码中使用固定的rotation_offset_in_radians(如-45°、135°)补偿边角位置,但这些角度仅适用于正方形——非正方形矩形的边角到中心的角度并非固定值(例如宽200、高100的矩形,右上角到中心的角度约为26.57°,而非-45°)。固定偏移角导致初始旋转时,计算角度与实际点击位置的角度不匹配,从而出现跳转。

解决方案

核心思路是基于初始点击的边角位置计算旋转增量,而非依赖固定角度偏移:

  1. 旋转开始时,根据矩形实际宽高计算边角相对于旋转中心的原始向量
  2. 拖拽过程中,计算当前光标相对于中心的向量,通过两个向量的夹角差得到旋转增量
  3. 用初始旋转角度加上增量,得到最终旋转角度

修改后的代码

pub fn handle_rotating(
    composition: &CompositionRes,
    selected_nodes_query: &mut Query<
        (
            &mut RelativeTransformMixin,
            &AbsoluteTransformMixin,
            &DimensionMixin,
        ),
        With<Selected>,
    >,
    event: &CursorMovedOnComposition,
    corner: u8,
    initial_rotation: f32,
) {
    let CursorMovedOnComposition {
        position: cursor_position,
        ..
    } = event;
    let cursor_position = transform_point_to_view_box(composition, cursor_position, true);

    selected_nodes_query.for_each_mut(
        |(mut relative_transform_mixin, absolute_transform_mixin, dimension_mixin)| {
            let relative_pivot_point = Vec2::new(
                dimension_mixin.width as f32 / 2.0,
                dimension_mixin.height as f32 / 2.0,
            );
            let absolute_pivot_point =
                apply_transform_to_point(absolute_transform_mixin.0, relative_pivot_point);

            // 1. 根据边角类型计算相对于自身中心的位置
            let relative_corner = match corner {
                c if c == (HandleSide::Top as u8 | HandleSide::Left as u8) => {
                    Vec2::new(-dimension_mixin.width as f32 / 2.0, -dimension_mixin.height as f32 / 2.0)
                }
                c if c == (HandleSide::Top as u8 | HandleSide::Right as u8) => {
                    Vec2::new(dimension_mixin.width as f32 / 2.0, -dimension_mixin.height as f32 / 2.0)
                }
                c if c == (HandleSide::Bottom as u8 | HandleSide::Right as u8) => {
                    Vec2::new(dimension_mixin.width as f32 / 2.0, dimension_mixin.height as f32 / 2.0)
                }
                c if c == (HandleSide::Bottom as u8 | HandleSide::Left as u8) => {
                    Vec2::new(-dimension_mixin.width as f32 / 2.0, dimension_mixin.height as f32 / 2.0)
                }
                _ => Vec2::ZERO,
            };

            // 2. 转换为旋转前的绝对边角位置
            let initial_corner_position = apply_transform_to_point(absolute_transform_mixin.0, relative_corner);

            // 3. 计算初始边角向量与当前光标向量
            let initial_corner_vector = initial_corner_position - absolute_pivot_point;
            let current_cursor_vector = cursor_position - absolute_pivot_point;

            // 4. 计算向量夹角差作为旋转增量
            let initial_angle = initial_corner_vector.y.atan2(initial_corner_vector.x);
            let current_angle = current_cursor_vector.y.atan2(current_cursor_vector.x);
            let rotation_delta = current_angle - initial_angle;

            // 5. 应用最终旋转角度
            let final_rotation_angle = initial_rotation + rotation_delta;
            relative_transform_mixin.0 = set_rotation(
                relative_transform_mixin.0,
                final_rotation_angle,
                relative_pivot_point,
            );
        },
    );
}

关键改进说明

  • 移除固定角度偏移,改用矩形实际宽高计算边角初始位置,适配任意宽高比
  • 旋转增量基于初始边角向量与当前光标向量的夹角差,确保旋转行为完全跟随光标拖拽轨迹
  • 初始点击点与旋转行为完全对齐,彻底解决非正方形矩形的旋转跳转问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:29:59