使用枢轴点缩放画布后,x 和 y 坐标错误

2023-12-01

我正在尝试在画布上实现缩放,该缩放应集中在枢轴点上。缩放工作正常,但之后用户应该能够选择画布上的元素。问题是,我的平移值似乎不正确,因为它们的偏移量与我不缩放到枢轴点的值不同(缩放没有枢轴点并拖动效果很好)。 我使用了一些代码这个例子.

相关代码是:

class DragView extends View {

private static float MIN_ZOOM = 0.2f;
private static float MAX_ZOOM = 2f;

// These constants specify the mode that we're in
private static int NONE = 0;
private int mode = NONE;
private static int DRAG = 1;
private static int ZOOM = 2;
public ArrayList<ProcessElement> elements;

// Visualization
private boolean checkDisplay = false;
private float displayWidth;
private float displayHeight;
// These two variables keep track of the X and Y coordinate of the finger when it first
// touches the screen
private float startX = 0f;
private float startY = 0f;
// These two variables keep track of the amount we need to translate the canvas along the X
//and the Y coordinate
// Also the offset from initial 0,0
private float translateX = 0f;
private float translateY = 0f;

private float lastGestureX = 0;
private float lastGestureY = 0;

private float scaleFactor = 1.f;
private ScaleGestureDetector detector;
...

private void sharedConstructor() {
    elements = new ArrayList<ProcessElement>();
    flowElements = new ArrayList<ProcessFlow>();
    detector = new ScaleGestureDetector(getContext(), new ScaleListener());
}

/**
 * checked once to get the measured screen height/width
 * @param hasWindowFocus
 */
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
    super.onWindowFocusChanged(hasWindowFocus);
    if (!checkDisplay) {
        displayHeight = getMeasuredHeight();
        displayWidth = getMeasuredWidth();
        checkDisplay = true;
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    ProcessBaseElement lastElement = null;

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            mode = DRAG;

            // Check if an Element has been touched.
            // Need to use the absolute Position that's why we take the offset into consideration
            touchedElement = isElementTouched(((translateX * -1) + event.getX()) / scaleFactor, (translateY * -1 + event.getY()) / scaleFactor);


                //We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated
                //amount for each coordinates This works even when we are translating the first time because the initial
                //values for these two variables is zero.
                startX = event.getX() - translateX;
                startY = event.getY() - translateY;
            }
            // if an element has been touched -> no need to take offset into consideration, because there's no dragging possible
            else {
                startX = event.getX();
                startY = event.getY();
            }

            break;

        case MotionEvent.ACTION_MOVE:
            if (mode != ZOOM) {
                if (touchedElement == null) {
                    translateX = event.getX() - startX;
                    translateY = event.getY() - startY;
                } else {
                    startX = event.getX();
                    startY = event.getY();
                }
            }

            if(detector.isInProgress()) {
                lastGestureX = detector.getFocusX();
                lastGestureY = detector.getFocusY();
            }

            break;

        case MotionEvent.ACTION_UP:
            mode = NONE;

            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            mode = ZOOM;

            break;
        case MotionEvent.ACTION_POINTER_UP:
            break;
    }

    detector.onTouchEvent(event);
    invalidate();

    return true;
}

private ProcessBaseElement isElementTouched(float x, float y) {
    for (int i = elements.size() - 1; i >= 0; i--) {
        if (elements.get(i).isTouched(x, y))
            return elements.get(i);
    }
    return null;
}

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();

    if(detector.isInProgress()) {
        canvas.scale(scaleFactor,scaleFactor,detector.getFocusX(),detector.getFocusY());
    } else
        canvas.scale(scaleFactor, scaleFactor,lastGestureX,lastGestureY);     // zoom

//        canvas.scale(scaleFactor,scaleFactor);

    //We need to divide by the scale factor here, otherwise we end up with excessive panning based on our zoom level
    //because the translation amount also gets scaled according to how much we've zoomed into the canvas.
    canvas.translate(translateX / scaleFactor, translateY / scaleFactor);

    drawContent(canvas);

    canvas.restore();
}

/**
 * scales the canvas
 */
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        scaleFactor *= detector.getScaleFactor();
        scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
        return true;
    }
}
}

元素以其在画布上的绝对位置保存(考虑到拖动)。我怀疑我没有将新的偏移量从枢轴点转移到translateX and translateY正在考虑中,但我不知道应该在哪里以及如何执行此操作。 任何帮助,将不胜感激。


好的,所以您基本上是在围绕某个枢轴点 {Px, Py} 缩放视图后,尝试找出某个屏幕 X/Y 坐标对应的位置。

那么,让我们尝试分解它。

为了便于论证,我们假设 Px & Py = 0,并且 s = 2。这意味着视图围绕视图的左上角缩放了 2 倍。

在本例中,屏幕坐标 {0, 0} 对应于视图中的 {0, 0},因为该点是唯一未更改的点。一般来说,如果屏幕坐标等于枢轴点,则没有变化。

如果用户点击其他点(比如 {2, 3}),会发生什么?在本例中,曾经的 {2, 3} 现在已从枢轴点(即 {0, 0})移动了 2 倍,因此相应的位置为 {4, 6}。

当轴心点为 {0, 0} 时,这一切都很容易,但如果轴心点不是 {0, 0} 时会发生什么?

好吧,让我们看看另一种情况 - 枢轴点现在是视图的右下角(宽度 = w,高度 = h - {w,h})。同样,如果用户点击相同的位置,那么对应的位置也是{w, h},但是假设用户点击了其他位置,例如{w - 2, h - 3}?这里出现相同的逻辑:翻译后的位置是{w - 4, h - 6}。

概括而言,我们要做的是将屏幕坐标转换为平移坐标。我们需要对收到的 X/Y 坐标执行与对缩放视图中的每个像素执行的操作相同的操作。

Step 1- 我们想根据枢轴点平移 X/Y 位置:

X = X - Px
Y = Y - Py

Step 2- 然后我们缩放 X 和 Y:

X = X * s
Y = Y * s

Step 3- 然后我们翻译回来:

X = X + Px
Y = Y + Py

如果我们将其应用于我给出的最后一个示例(我将仅针对 X 进行演示):

Original value: X = w - 2, Px = w
Step 1: X <-- X - Px = w - 2 - w = -2
Step 2: X <-- X * s = -2 * 2 = -4
Step 3: X <-- X + Px = -4 + w = w - 4

将其应用于缩放之前收到的相关 X/Y 后,该点将被平移,以便它相对于缩放状态。

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用枢轴点缩放画布后,x 和 y 坐标错误 的相关文章

  • ACTION_VIEW 的 Intent.createChooser 仅显示默认浏览器

    我正在尝试使用 Intent createChooser 显示应用程序选择器对话框 该对话框将列出用户手机中所有可用的网络浏览器 我正在使用下面的代码 Intent browserIntent new Intent Intent ACTIO
  • 任务“:app:dexDebug”执行失败

    我目前正在处理我的项目 我决定将我的 Android Studio 更新到新版本 但在我导入项目后 它显示如下错误 Information Gradle tasks app assembleDebug app preBuild UP TO
  • 未找到 Gradle DSL 方法:“versionCode()”

    构建我的 Android 项目时遇到问题 我使用Grgit https github com ajoberstar grgit填写versionCode and versionName在 gradle 中 一切工作正常 直到我将 Andro
  • ImageView 中的全尺寸图像

    我正在尝试在 ImageView 中绘制图像 但我希望它不缩放 并根据需要使用滚动条 我怎样才能做到这一点 现在我只有一个可绘制集作为 XML 中 ImageView 的 android src 这会自动缩放图像以适应屏幕宽度 我读到这可能
  • 如何改变android中menuItem的背景颜色?

    我正在以编程方式将菜单项添加到菜单中 我想在选择特定项目时添加背景颜色 如何为 menuItem 添加背景 您的回答将不胜感激 虽然其他答案提供了更改样式 这会影响all菜单项 据我了解 需要更改一个菜单项 我建议你使用android ac
  • 在 Android 中的活动、服务和应用程序之间传递变量

    有人可以给我提供以下活动 服务 应用程序组合的示例吗 我拥有这三个 但我已经把我的应用程序弄得一团糟 试图在这个地方传递一堆变量 现在我不知道发生了什么 请注意 我是 Android 新手 最近我一直在努力解决这个问题 因为有很多方法可以实
  • android 谷歌+登录定制

    我正在创建一个 Android 应用程序 现在我正在实现社交网络登录 Facebook 按钮很好 但 google 按钮的语言与 Facebook 不同 另外 它只说 登录 我想让它说 用谷歌登录 我是 android 编程的新手 看到我需
  • Mailgun POST /messages API 总是抛出 401 禁止

    我正在尝试使用改造库在 Android 中发送 Mailgun POST messages API 请求 以下是改装要求 HTTP POSThttps api key xxx v3 sandboxxxx messages https api
  • Google Inbox 类似 RecyclerView 项目打开动画

    目前 我正在尝试实现 Google Inbox 例如RecyclerView行为 我对电子邮件打开动画很好奇 我的问题是 该怎么做 我的意思是 他们使用了哪种方法 他们用过吗ItemAnimator dispatchChangeStarti
  • 无法将 Tesseract OCR 模块添加到 Android Studio

    我按照此处找到的分步指南进行操作 https www codeproject com Articles 840623 Android Character Recognition https www codeproject com Artic
  • Android - 除了普通 SSL 证书之外还验证自签名证书

    我有一个通过 SSL 调用 Web 服务的 Android 应用程序 在生产中 我们将拥有由受信任的 CA 签名的普通 SSL 证书 但是 我们需要能够支持自签名证书 由我们自己的 CA 签名 我已经成功实施了接受自签名证书的建议解决方案
  • 6:需要显示BuyFlow UI

    There is a problem when i am click on payWithGoogle Button I am implementing Google Pay in my Android Application and wh
  • 在 Android 中使用 iText 读取或打开 PDF 文件

    我是 Android 应用程序开发新手 使用 iText 我完成了 PDF 创建并在创建的文件上写入 现在我想阅读该 PDF 文件 如何使用 iText 打开或阅读 PDF 文件 例子将是可观的 那么提前 哪个是渲染 PDF 文件的最佳库
  • 当应用程序未运行时如何堆叠 Firebase Cloud Messaging 通知?

    我在用Firebase Cloud Messaging将推送通知从我的服务器发送到我的 Android 应用程序 当应用程序运行时 通知是stacked因为我将它们设置为我的一个组FirebaseMessagingService 这很好 但
  • onTouchEvent()中如何区分移动和点击?

    在我的应用程序中 我需要处理移动和单击事件 一次点击是由一个 ACTION DOWN 操作 多个 ACTION MOVE 操作和一个 ACTION UP 操作组成的序列 理论上 如果您收到 ACTION DOWN 事件 然后收到 ACTIO
  • 如何在新标签 android webview 中打开链接? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经使用 webview 创建了一个 android 应用程序来显示我的网站 我什至想添加在新选项卡中打开链接的功能 但我找不到任何
  • 带有空白白屏的 WebView

    我在 DialogFragment 中有一个 webview 它使用以下方式显示文档和 PDF它可以进行几次尝试 但如果用户尝试频繁打开和关闭对话框 webview 将显示空白屏幕 我已经尝试了所有的线程link1 https stacko
  • 如何更改锁屏自定义文本(所有者信息)?

    我写了程序代码 String message This is test Settings System putString context getContentResolver Settings Secure LOCK PATTERN EN
  • 按名称查找视图

    是否可以通过名称而不是 id 来查找视图 findViewById R id someView 但我想做这样的事情 findViewByName someView 在处理 xml 时 您必须通过标识符查找视图 但是您可以使用以下方式查找标识
  • 基于BluetoothChat示例通过蓝牙套接字发送文件

    大家好 根据我之前问的一个问题 我已经能够将文件转换为其他字节数组 以便使用以下写入方法 public void sendFile Log d TAG sending data InputStream inputStream null Ur

随机推荐

  • 如何通过 docker run 将参数传递给 Shell 脚本

    我是码头工人世界的新手 我必须调用一个 shell 脚本 该脚本通过 docker 容器获取命令行参数 例如 我的 shell 脚本如下所示 bin bash echo 1 Dockerfile 看起来像这样 FROM ubuntu 14
  • 如何扩展最终类?(Reflection,Javassist)

    我有一个 JAR 文件 它有大量的类 一 我需要的被设置为最终的 所以我不能扩展它 有一种方法 我基本上必须扩展和修复 否则一切都会崩溃 我怎样才能做到这一点 我知道 Reflection 和 Javassist 可以用于此目的 但我不知道
  • 使用 AngularJS 跟踪 Google Analytics 页面浏览量

    我正在使用 AngularJS 作为前端来设置一个新应用程序 客户端的一切都是通过 HTML5 Pushstate 完成的 我希望能够在 Google Analytics 中跟踪我的页面浏览量 如果您正在使用ng view在你的 Angul
  • SystemJS:加载构建文件

    我的 SystemJS 文件如下所示 function global map tells the System loader where to look for things var map angular2 boot app dist a
  • iOS 7 - viewDidLoad 和 viewDidAppear 之间的区别

    抱歉 这本身可能不是一个编程问题 而更多的是对 iOS 生命周期函数性质的询问 我有一个应用程序 其中有一个函数可以创建四个数组并通过数据库查询填充它们 首先 我从viewDidLoad函数 但是 每当加载视图时 视图实际显示之前都需要一段
  • 使用 JAXB 进行灵活编组

    我希望有一种灵活的方式来编组对象 单个对象的详细版本和多个对象版本的不太详细版本 例如 考虑我的部门模型 获取 位置 1
  • 对结构队列进行排序

    我目前有一个队列 其中包含用户指定数量的结构 称为Process 进程由 pid 突发和到达组成 我想按到达时间对队列进行排序 但我完全不知道从哪里开始 这是一些伪代码来帮助说明我想说的内容 struct Process int pid i
  • cmake找不到java,但是已经安装了

    我正在尝试使用 cmake 构建一个项目 这个项目主要使用java 问题是在代码中 find package Java REQUIRED 我收到以下错误 CMake Error at usr share cmake 2 8 Modules
  • 将日期字符串格式化为适合 Google 日历作为参数

    我有一个代表 2014 July 2014 等数据的字符串 我正在 javacript 中格式化此日期 以便我可以将其用作 Google 日历图表的参数 E g var x 2014 July 12 var splitted x spilt
  • 从 Blob 保存到本地文件

    我有一个难题要问你 我已经为此苦苦挣扎了一段时间 我正在寻找一种解决方案 我可以将文件保存到用户计算机 而无需本地存储 因为本地存储有 5MB 限制 我想要 保存到文件 对话框 但我想要保存的数据只能在 JavaScript 中使用 我想阻
  • Java String.replace/replaceAll 不工作

    因此 我试图解析 Java 中包含 左 方括号的字符串输入 我有str replace 但这绝对没有任何作用 我试过了replaceAll另外 具有多个不同的正则表达式 但输出始终保持不变 我想知道这是否可能是由于我所有的反斜杠字符都显示为
  • 影响 d3.js 中多个单独图表的交互?

    我正在尝试在 d3 js 中创建一个数据可视化 其中包含两个图表 一个平行轴图和水平颜色条图 我只是起了这个名字 但它基本上是一系列彩色矩形 平行轴图中的每条线都与颜色条图中的一组矩形相关联 现在 将鼠标悬停在给定的线上会突出显示该行 并将
  • 将 docker-compose 与 docker swarm 结合使用

    我在用着docker 1 12 1我有一个简单的 docker compose 脚本 version 2 services jenkins slave build slave image jenkins slave 1 0 restart
  • React-Native:无法在 Android 设备上以发布模式显示远程图像

    我正在我的 Android 设备 三星 9 Android 9 API 28 中运行一个简单的反应本机应用程序 因此在调试模式下 使用此命令行可以正常工作 react native run android 这是结果 但在释放模式下 reac
  • Jersey/REST--NoSuchMethodError:com.sun.jersey.core.reflection.ReflectionHelper.getContextClassLoaderPA()Ljava/security/Privilege

    当尝试使用 jersey 构建 REST 服务时 我收到 NoSuchMethodError 错误 任何帮助将非常感激 我的 POM xml
  • GetExtendedTcpTable 不返回与 netstat -ano 相同的结果

    我使用此代码来获取我的电脑中打开的端口的列表以及使用每个端口的应用程序 string Port GetListOfTcpPorts string ApplicationName string result string aux string
  • 通过测试侦听器删除(重复)失败的 TestNG 结果

    类似于这里发布的解决方案TestNG 重试失败的测试不会输出正确的测试结果 我尝试在 onFinish ITestContext context 期间使用测试侦听器删除 重复的 测试结果 尽管使用 context getFailedTest
  • Visual Studio 2012如何绘制窗口边框?

    如何使用 Windows 窗体实现与新的 Visual Studio 2012 主窗口中看到的相同的 alpha 边框效果 它的窗户似乎在发光 所以我不确定这是否是最好的方法 但是如果您使用 Spy 32 位 并查看窗口 您可以看到在 Vi
  • 使用 Sparklyr 完成时间序列

    我试图在我的时间序列数据集中找到丢失的分钟数 我为一个小样本的本地性能编写了一个 R 代码 test lt dfv gt mutate timestamp as POSIXct DaySecFrom UTC gt complete time
  • 使用枢轴点缩放画布后,x 和 y 坐标错误

    我正在尝试在画布上实现缩放 该缩放应集中在枢轴点上 缩放工作正常 但之后用户应该能够选择画布上的元素 问题是 我的平移值似乎不正确 因为它们的偏移量与我不缩放到枢轴点的值不同 缩放没有枢轴点并拖动效果很好 我使用了一些代码这个例子 相关代码