javascript - 如何计算点击可拖动 Canvas 元素的位置?

标签 javascript reactjs redux html5-canvas

我需要帮助解决一个非常困难的问题。我目前正在使用 React 和 Redux 制作游戏。在这个游戏中,我使用 Canvas 从我的 redux 商店创建 map 数据。目前 map 只是一个黑白方 block 矩阵。假设我想在单击正方形时更改其颜色,同时保持拖动元素的能力。问题是很难精确定位鼠标点击的位置,因为元素可以拖动到页面上的任何位置。据我所知,似乎没有任何 mouseclick 事件对象属性能够告诉我。我以为 offsetX 和 offsetY 会告诉我,但当 Canvas 对象出于某种原因移动时,它们似乎不会保持不变。

我在这个项目中使用 React 和 Redux,并且 CanvasMap 元素包装在这个库中的 Draggable 中:https://www.npmjs.com/package/react-draggable#draggablecore

import React from 'react'
import { connect } from 'react-redux'
import './CanvasMap.css'

class CanvasMap extends React.Component{

  componentDidMount() {
    const map = this.props.map //Data representing the map
    const canvas = this.refs.canvas
    const context = canvas.getContext('2d')

    //Building the map on the canvas
    for(let i = 0; i < map.length; i++){
      for(let j = 0; j < map[i].length; j++){
        const x=i*100
        const y=j*100
        const isBlackSquare= map[i][j] === 'black' ? true : false
        if(isBlackSquare) context.fillRect(x, y, 100, 100)
        else context.strokeRect(x, y, 100, 100)
      }
    }

    function handleClick(e){
      //None of the event properties seem to stay the same when the canvas is moved
      console.log(e)
    }


    canvas.addEventListener('click', handleClick)
  }

  render(){
    return (
      <div className='Map'>
        <canvas ref='canvas' width={8000} height={8000} />
      </div>
    )
  }
}

function mapStateToProps(state){
  return {
    map: [...state.map]
  }
}

const connectedComponent = connect(mapStateToProps)(CanvasMap)
export { connectedComponent as CanvasMap }

最佳答案

在大多数情况下,当您单击 HTML 元素时,您可以使用 rectangleBounding Box 并从中获取协调器,例如

domRect = element.getBoundingClientRect();

在 Canvas 点击位置有点困难

这是我前一段时间在 Canvas 上拖动鼠标时绘制的脚本。也许你可以应用这个方法

<html>
    <head>
    <style>

    * { margin:0; padding:0; } /* to remove the top and left whitespace */

    html, body { width:100%; height:100%; } /* just to be sure these are full screen*/

    canvas { display:block; } /* To remove the scrollbars */



    </style>
    </head>

    <body>
    <canvas id="canvas" ></canvas>
    <script>



    ////////////////////////////////////////


    (function() {
        var canvas = document.getElementById('canvas');
        var ctx = canvas.getContext('2d');

        var elemLeft = canvas.offsetLeft;
        var elemTop = canvas.offsetTop;
        var BB=canvas.getBoundingClientRect();
        var offsetX=BB.left;
        var offsetY=BB.top;

        // resize the canvas to fill browser window dynamically
        window.addEventListener('resize', resizeCanvas, false);

        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;

            /**
                * Your drawings need to be inside this function otherwise they will be reset when 
                * you resize the browser window and the canvas goes will be cleared.
            */
            drawStuff(); 
        }
        resizeCanvas();

        function drawStuff() {
            // do your drawing stuff here
            var img = new Image();              

            img.src = 'images/3PkBe.gif';
            img.onload = function()
            {
                //var canvas = document.getElementById('canvas');
                // create pattern
                var ptrn = ctx.createPattern(img, 'repeat'); // Create a pattern with this image, and set it to "repeat".
                ctx.fillStyle = ptrn;
                ctx.fillRect(0, 0, canvas.width, canvas.height); // context.fillRect(x, y, width, height);
                ctx.shadowBlur=20;
                //ctx.shadowColor="black";
                //ctx.fillStyle="green";
                //ctx.fillRect(20,160,100,80);


                ctx.strokeStyle = "lightgray";

                //var canvasOffset = canvas.offset();
                //var offsetX = canvasOffset.left;
                //var offsetY = canvasOffset.top;

                var mouseIsDown = false;
                var lastX = 0;
                var lastY = 0;
                var elements = [];

                makeShip( 30 , 30,120, 120,  '#119' , "romea");
                makeShip( 30, 160,120, 120,  '#393', "fomar");
                makeShip( 30, 290,120, 120,  '#955', "ojab");
                makeShip( 30, 420,120, 120,  '#6ff', "eliot");
                // Add event listener for `click` events.

                canvas.addEventListener('click', function(event) {

                    var x = event.pageX - elemLeft,
                    y = event.pageY - elemTop;
                    console.info(x, y);
                    elements.forEach(function(element) {

                        if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
                            console.log(element.name);
                        }
                    });





                }, false);

                canvas.addEventListener('mousedown', function(event) {

                        var x = event.pageX - elemLeft,
                    y = event.pageY - elemTop;
                    console.info(x, y);
                    elements.forEach(function(element) {

                        if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
                            console.info(element.name);
                            handleMouseDown(element);
                        }
                    });



                }, false);

                canvas.addEventListener('mousemove', function(event) {


                    var x = event.pageX - elemLeft,
                    y = event.pageY - elemTop;
                    console.info(x, y);
                    elements.forEach(function(element) {

                        if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
                            console.info(element.name);
                            handleMouseMove(element,x,y);
                        }
                    });

                }, false);

                canvas.addEventListener('mouseup', function(event) {


                    var x = event.pageX - elemLeft,
                    y = event.pageY - elemTop;
                    //console.info(x, y);

                    elements.forEach(function(element) {

                        //if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
                            console.info(element.name + "mouse up evenr=========");
                            handleMouseUp(element);
                    //}
                    });

                }, false);




                function makeShip(x, y, width, height, colour,ShipName) {
                    var ship = {
                        name: ShipName,
                        colour: colour,
                        width: width,
                        height: height,
                        x: x,
                        y: y
                    }
                    elements.push(ship);
                    return (ship);
                }
                function drawShip(ship) {

                    //ctx.fillStyle = ship.colour;
                    //ctx.fillRect(ship.x, ship.y, ship.width, ship.height);
                    //ctx.fillRect(element.x, element.y, element.width, element.height);
                }

                function drawAllShips() {
                    //  ctx.clearRect(0, 0, canvas.width, canvas.height);
                    for (var i = 0; i < elements.length; i++) {
                        var ship = elements[i]
                        //drawShip(ship);
                    ctx.fillStyle = ship.colour;
                    ctx.fillRect(ship.x , ship.y, ship.width, ship.height);
                        //   ctx.fillStyle = ship.fill;
                        //   ctx.fill();
                        //    ctx.stroke();
                    }
                }




                // Add element.
                //elements.push({
                //colour: '#05EFFF',
                //width: 150,
                //height: 100,
                //x: 20,
                //y: 15
            //});

            // Render elements.
            //  elements.forEach(function(element) {
            //      ctx.fillStyle = element.colour;
            //      ctx.fillRect(element.x, element.y, element.width, element.height);
            //  });

            drawAllShips();


            function handleMouseDown(e) {
              mouseX = e.x ;
              mouseY = e.y ;

                //mouseX = parseInt(e.x - offsetX);
                //mouseY = parseInt(e.y - offsetY);
                console.log("===========Problem "+mouseX);
                // mousedown stuff here
                lastX = mouseX;
                lastY = mouseY;
                mouseIsDown = true;
                //alert("mouse Handle");

            }

            function handleMouseUp(e) {
                //mouseX = parseInt(e.clientX - offsetX);
                //mouseY = parseInt(e.clientY - offsetY);

     ctx.onmousemove = null;
                // mouseup stuff here
                mouseIsDown = false;
                return
            }

            function handleMouseMove(e,x,y) {
                if (mouseIsDown) {



                //console.log(' no fuck');
                mouseX = e.x ;
                mouseY = e.y ;
                console.log(e.name+"is truing to drag");

                // mousemove stuff here
                //for (var i = 0; i < elements.length; i++) {

                        //if (ctx.isPointInPath(mouseX, mouseY)) {
                    //console.log('============== no fuck');
                    var ship =e;// elements[i];
                    ship.x = x-15;//(mouseX - lastX);
                    ship.y = y-20;//(mouseY -lastY);
                //  ship.right = ship.x + ship.width;
                //  ship.bottom = ship.y + ship.height;

                    //drawShip(ship);
            //}

            //}
                lastX = mouseX;
                lastY = mouseY;
                drawAllShips(); 
                }
            }

            <!-- ctx.mousedown(function (e) { -->
                <!-- handleMouseDown(e); -->
            <!-- }); -->
            <!-- ctx.mousemove(function (e) { -->
                <!-- handleMouseMove(e); -->
            <!-- }); -->
            <!-- ctx.mouseup(function (e) { -->
                <!-- handleMouseUp(e); -->
            <!-- }); -->

        }



    }
    })();
    </script>
    </body>
    </html>         

关于javascript - 如何计算点击可拖动 Canvas 元素的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58986251/

相关文章:

javascript - 媒体源 API 和 mp4

javascript - 导入 React,{Component} 而不仅仅是 React 有什么好处?

react-native - 使用 Redux 工具包中的 createEntityAdapter 时如何将实体作为类组件中的数组获取?

javascript - ReactJs 和样式组件,无法在输入字段中键入任何内容

reactjs - 如何管理接受 yield select 参数的选择器?

javascript - jQuery dataTable 显示最近的记录

javascript - 如何在这里添加点击灯箱到div img?

javascript - 如何在 php 语言(或 javascript)上将 InDesign 文件与 XML 标签文件粘合?

javascript - Redux 形式 v5 : How to clear/hide submit error after field edited

javascript - 使用条件渲染时出现警告 : Functions are not valid as a React child,