V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qq309187341
V2EX  ›  Vue.js

有偿!昨天问了一下,还是没有解决问题,直接有偿求解。

  •  1
     
  •   qq309187341 · 2022-11-02 02:40:59 +08:00 · 3724 次点击
    这是一个创建于 755 天前的主题,其中的信息可能已经有所发展或是发生改变。
    需要一个检测方法。
    touch:是触摸点坐标( x,y )
    item:是画布中的元素(含元素的,x,y,w,h,以及旋转角度 r)
    iconSize:是元素周围的按钮的大小,初始为 24px ,包含了删除,旋转,缩放等等。
    getTouchPos(touch,item,iconSize){}

    需要通过这个方法检测到当前点击是否在元素上,如何是在元素上是否在元素的删除,旋转,缩放等按钮。不在元素上返回 false 。

    难点在于元素进行旋转之后,点位也发生了变化!!!

    大致样子如下图。
    https://ibb.co/kGJ3bPr

    发了好几次帖子,大家都只给方法,奈何数字太差,尝试了很多次都是旋转之后点位没有精确检测到。

    能解决的大佬可以联系我,有偿。也可以直接贴上代码,万分感谢。发光发热!!!
    26 条回复    2022-11-12 15:32:23 +08:00
    stein42
        1
    stein42  
       2022-11-02 03:13:59 +08:00
    我可以解决。
    base64: d3g6IGktYW0tc3RlaW4K=
    eason1874
        2
    eason1874  
       2022-11-02 03:24:48 +08:00
    说实话我都没看懂你的需求。。。可能是因为我没写过 canvas

    以前写 div 的时候,我是画布元素绑定一个事件,编辑按钮又绑定自己的事件,所有按钮都有一个 class 或者 attr 表明它是可操作的按钮(用来查询)。大部分情况下,点按钮只会触发按钮事件,点画布只会触发画布事件,但是偶尔也会同时触发,所以为了避免同时触发两个事件,画布事件触发时会先查询有没有 mouseover 的按钮,有的话就不执行本次触发事件
    Curtion
        3
    Curtion  
       2022-11-02 09:43:21 +08:00
    射线法 ?
    why1001
        4
    why1001  
       2022-11-02 09:52:46 +08:00
    Fabric.js 可以看看这个 canvas 的库,对你有没有用。
    rekulas
        5
    rekulas  
       2022-11-02 09:53:26 +08:00
    你如果实在不精通计算不如考虑下类库?比如 pixijs 之类的,几十 kb 非常精简,检测啥的完全不用你操心只需实现逻辑就行了
    qq309187341
        6
    qq309187341  
    OP
       2022-11-02 09:56:25 +08:00
    @why1001 我试过了。那个四个角控制角无法自定义,我需要放图片。而且隐藏掉控制角,还需要自己去实现相关操作。帮助不大。所以自己能自己实现了。目前就差个检测函数计算方式了。
    rekulas
        7
    rekulas  
       2022-11-02 09:57:06 +08:00
    demo https://pixijs.io/examples/#/interaction/custom-mouse-icon.js
    无论你是旋转缩放移动之后都是类库自动处理,而且 pixi 优先使用 webgl 处理图像,性能极高,很多人手写都比不过
    Zzzz77
        8
    Zzzz77  
       2022-11-02 10:01:23 +08:00
    额,这个问题其实很常见,可以参考 konva.js 的做法,核心在于:为 canvas 中每一个元素赋一个随机的颜色(但不显示),然后通过对比鼠标点击位置像素的颜色值来判断。
    qq309187341
        9
    qq309187341  
    OP
       2022-11-02 10:02:34 +08:00
    @rekulas 因为其他的逻辑都已经写完了,现在只差一个检测算法了。推到从来代价太大了,而且相关的库不太了解,不知道能否实现。粗看一下,好像都不太能满足。所以看看有没有大佬能帮我处理一下检测算法。其实我自己也处理了一下,但是旋转之后还是存在点击某些位置,检测不到,应该是我计算方式不对。
    Zzzz77
        10
    Zzzz77  
       2022-11-02 10:11:52 +08:00
    补充:假设你有一个画布,上面有一个圆一个正方形。那么你绘制的时候可以绘制两个 canvas ,一个是你正常显示的 canvas1 ,另一个 canvas 中为内部元素赋予随机颜色值,例如正方形红色,圆形绿色,然后把这个 canvas 给 display none ,我们命名为 canvas2 。最后鼠标点击的时候,获取到鼠标坐标,通过该坐标在 canvas2 中获取到对应位置的颜色值,如果是红色就代表点在正方形上,绿色就表示点在圆形上,以此类推
    qq309187341
        11
    qq309187341  
    OP
       2022-11-02 10:18:01 +08:00
    @Zzzz77 感觉你说的并不能解决我目前的问题。因为 canvas 上可以是用户添加的很多图片,并且他们都可能会叠放起来。目前的方式是通过获取点击位置的点,然后去判断元素所存放的数组,因为 canvas 是越后面的元素展示上越在前面,所以最后一个符合的元素就是我所点击的目标。
    qq309187341
        12
    qq309187341  
    OP
       2022-11-02 10:24:11 +08:00
    @Zzzz77 如果元素没有经过旋转,去检测是否匹配是很简单的。但是经过旋转了之后,整个图形变化了,我的检测方式就没有了。我尝试用正弦余弦去计算,但是还是失败了,可能是我计算方式不对。数学太菜了,也试了试大佬说的极坐标,但是还是存在一些点位无法检测到。应该是我自己的数据不对。所以希望那个大佬直接帮我写一些检测方法的内容
    Zzzz77
        13
    Zzzz77  
       2022-11-02 10:30:26 +08:00
    一回事啊,和叠不叠起来没关系,赋予颜色值的新 canvas 是原样把原 canvas 再绘制一遍,该什么层级还是什么层级,你要做的只是将新画布上对应点的颜色和你预先生成的颜色做对比就行,这个是画板类应用的常见处理方式
    Zzzz77
        14
    Zzzz77  
       2022-11-02 10:34:11 +08:00
    如果说要硬啃几何方法来实现,要么参考 fabric.js 的源码( fabric.js 也并不完全准确),要么报出有偿金额请图形学大佬帮忙了,不然估计你问不出个结果来....
    cccchg
        15
    cccchg  
       2022-11-02 10:59:35 +08:00
    你这个需求我 去年做过 可以给你提供代码 参考 现在我也看不懂当时咋写的了
    cccchg
        16
    cccchg  
       2022-11-02 11:01:39 +08:00
    const [centerX, centerY] = sprite.center;
    const x1 = this.rotateStartX - centerX;
    const y1 = this.rotateStartY - centerY;
    const x2 = touchX - centerX;
    const y2 = touchY - centerY;


    const numerator = x1 * y2 - y1 * x2;
    const denominator =
    Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2)) *
    Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2));
    const sin = numerator / denominator;
    const angleDir = Math.asin(sin);

    sprite.setRotateAngle(angleDir);
    this.rotateStartX = touchX;
    this.rotateStartY = touchY;
    yaphets666
        17
    yaphets666  
       2022-11-02 11:02:25 +08:00
    @qq309187341 fabric 就能做,有函数式的放大图片的方法。你看文档吧
    qq309187341
        18
    qq309187341  
    OP
       2022-11-02 11:05:26 +08:00
    @cccchg 有写方法都没有全。。。。方便提供一下源码么??
    cccchg
        19
    cccchg  
       2022-11-02 11:07:08 +08:00
    @qq309187341 我这个是微信小程序
    cy1027
        20
    cy1027  
       2022-11-02 11:11:29 +08:00
    说是有偿,结果在这里白嫖,然后别人做出来也不知道你给多少钱,然后一直否定别人的方法,不知道别人真的做出来之后你是不是还要否定,然后拒付尾款
    qq309187341
        21
    qq309187341  
    OP
       2022-11-02 11:24:52 +08:00
    @cy1027 大哥你是被人骗多了么?内心如何黑暗?我上面说的很清楚,哪位大佬直接帮我实现相关方法,私我给我代码我给他钱,也可以先加起来问问多少钱,再决定要不要帮我实现。或者好心人直接贴源码无偿,我也感谢。至于金额,能处理的人我给个一二百,也当意思意思。处理不了问个价格有什么用?你能不能处理,不能处理就看看就好。至于在这里质疑我是不是白嫖?再说了,上面除了有一个哥们贴了不完全的代码,其他人也只是给他方式而已。我也表示感谢大家能给我思路,但是我需要的是现实方法(我比较菜,没能力实现所以求助)
    churchill
        22
    churchill  
       2022-11-02 11:43:31 +08:00
    这个问题有这么纠结么,我昨天还随手写了个小示例,方法是检测线段相交
    如果仅仅是要知道点在里面还是外面可以更简单

    首先算出矩形的 4 个顶点坐标,如果你是自己实现的变换,那怎么算不用别人讲,如果是用了 canvas api ,那可以直接把 canvas 的矩阵拿来用 context.getTransform ,然后只需简单的做个乘法

    拿到顶点坐标后,代表每条边的向量与代表顶点到检测点的向量做一个叉乘,就可以知道结果了
    写成 js 代码大致这样
    ```
    isInside = true
    for (i = 0; i < vertices.length; i++) {
    const v1 = vertices[i]
    const v2 = vertices[(i + 1) % vertices.length]
    if (v2.sub(v1).cross(p.sub(v1)) < 0) {
    isInside = false ; break
    }
    }
    ```

    详细的讲解看这个,拖到后面讲 cross product 的部分
    https://www.bilibili.com/video/BV1X7411F744?p=2
    qq309187341
        23
    qq309187341  
    OP
       2022-11-02 11:52:24 +08:00
    @churchill 感谢大佬,昨天给我的 demo ,我试了一下,我转化到自己的项目上没成功,很郁闷,看不懂你的核心方式。。。不过刚才 1L 的大哥给我方法了,用正弦余弦函数处理。能满足需求了。发了 200 意思一下了。
    还是感谢大佬多次给我解答。感谢
    qq309187341
        24
    qq309187341  
    OP
       2022-11-02 11:54:45 +08:00
    谢谢各位,热心帮助。问题已经解决了。感谢 1L 大佬帮我处理了。虽然有偿但是能处理了就可以。之后看情况把源码发出来。给以后需要的(和我一样菜的) 朋友一些参考
    stein42
        25
    stein42  
       2022-11-02 11:55:21 +08:00   ❤️ 1
    已经帮 OP 解决了,也收到了红包。
    思路就是把触摸点相对于 canvas 的坐标,换回相对于元素(一个矩形)的坐标,再判断。
    由于 uniapp 没有 getTransform ,需要手动推导公式了。
    ActionFirst
        26
    ActionFirst  
       2022-11-12 15:32:23 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1050 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:20 · PVG 04:20 · LAX 12:20 · JFK 15:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.