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

基于ImGUI的2D画布鼠标中心缩放Y轴偏移问题排查

解决ImGUI画布围绕鼠标缩放时Y轴偏移问题

问题分析

当前缩放逻辑中X轴表现正常,但Y轴在放大时向上偏移、缩小时向下偏移,核心原因是缩放时的平移计算未匹配画布Y轴的坐标翻转逻辑——你的worldToScreen和screenToWorld函数中,屏幕Y轴方向与世界Y轴方向相反(屏幕Y向上数值减小,世界Y向上数值增大),直接用屏幕坐标计算偏移会导致Y轴方向错误。

解决方案

核心思路:先将鼠标屏幕坐标转换为世界坐标,计算缩放前后该点在世界空间的位置变化,再调整pan值确保鼠标指向的世界点始终停留在屏幕原位置。这种方式无需手动处理Y轴翻转,逻辑更可靠。

修改后的HandleInput函数代码:

void Canv::HandleInput(const ImVec2& canvasPosition, const ImVec2& canvasSize) {
    canvasPosition_ = canvasPosition;
    canvasSize_ = canvasSize;

    ImVec2 mousePosition = ImGui::GetMousePos();

    if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
        const auto mouse_delta = ImGui::GetIO().MouseDelta;
        pan -= ImVec2(mouse_delta.x, -mouse_delta.y) / (zoom * units_per_pixel);
    }

    // 修复后的缩放逻辑
    if ((ImGui::GetIO().MouseWheel != 0) 
      && ImGui::IsMouseHoveringRect(canvasPosition, canvasPosition + canvasSize)) {
        const float zoom_delta = ImGui::GetIO().MouseWheel * 0.1f;
        const float old_zoom = zoom;
        
        // 1. 将当前鼠标屏幕坐标转换为世界坐标
        ImVec2 mouse_world_old = screenToWorld(mousePosition);

        // 2. 更新缩放值
        zoom *= std::pow(2.0f, zoom_delta);
        zoom = std::clamp(zoom, 0.2f, 10.0f);

        // 3. 计算缩放后,原鼠标世界坐标对应的新屏幕位置,再转回世界坐标
        ImVec2 mouse_screen_new = worldToScreen(mouse_world_old);
        ImVec2 mouse_world_new = screenToWorld(mouse_screen_new);

        // 4. 调整pan,让鼠标指向的世界点保持不动
        pan += mouse_world_old - mouse_world_new;
    }
}

修改说明

  1. 用坐标转换替代手动计算偏移:通过screenToWorld和worldToScreen自动处理Y轴翻转,避免手动计算时的方向错误。
  2. 保持鼠标指向的世界点固定:缩放前记录鼠标对应的世界点,缩放后计算该点在新缩放比例下的屏幕位置,再转回世界坐标,最后调整pan让两个世界坐标重合,确保缩放围绕鼠标中心进行。

其他函数(worldToScreen、screenToWorld)及成员变量无需修改,平移逻辑保持原样即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:22:44