【问题标题】:Canvas stops tracking mouse after awhile画布在一段时间后停止跟踪鼠标
【发布时间】:2018-03-17 22:00:36
【问题描述】:

我遇到了一个奇怪的错误,我很难弄清楚。首先,这是代码:

const canvas = document.getElementById('canvas');
const canvasContainer = document.getElementById('canvas-container');
const ctx = canvas.getContext('2d');


function resizeCanvas() {
    canvas.width = canvasContainer.clientWidth;
    canvas.height = canvasContainer.clientHeight;
}



async function init() {
    window.addEventListener('resize', resizeCanvas)
    resizeCanvas();



    window.requestAnimationFrame(draw);

    let poly = [];

    canvas.addEventListener('click', ev => {
        let x = ev.clientX - canvas.offsetLeft;
        let y = ev.clientY - canvas.offsetTop;
        poly.push([x,y]);
    })



    window.addEventListener('keyup', ev => {
        if(ev.key === 'Escape') {
            poly.length = 0;
        }
    });

    let mousePos = null;

    canvas.addEventListener('mouseleave', ev => {
        mousePos = null;
    })

    canvas.addEventListener('mousemove', ev => {
        let x = ev.clientX - canvas.offsetLeft;
        let y = ev.clientY - canvas.offsetTop;
        mousePos = {x,y};
        console.log(x,y);
    })



    function draw() {
        // ctx.save();

        ctx.fillStyle = '#ADD5F8';

        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.fillStyle = '#C38F4C';

        if(poly.length >= 3) {
            ctx.beginPath();
            ctx.moveTo(...poly[0]);
            for(let i=1; i<poly.length; ++i) {
                ctx.lineTo(...poly[i]);
            }
            ctx.closePath();
            ctx.fill();
        }

        if(poly.length && mousePos) {
            ctx.beginPath();
            ctx.moveTo(...poly[0]);
            for(let i=1; i<poly.length; ++i) {
                ctx.lineTo(...poly[i]);
            }
            if(mousePos) {
                console.log(mousePos);
                ctx.lineTo(mousePos.x, mousePos.y);
            }
            ctx.strokeStyle = '#ff0000';
            ctx.stroke();
        }


        window.requestAnimationFrame(draw);
    }
}

function createImage(path) {
    return new Promise((resolve,reject) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = err => reject(err);
        img.src = path;
    })
}

async function createPattern(path, repetition='repeat') {
    // TODO: https://stackoverflow.com/a/21128933/65387
    const img = await createImage(path);
    return ctx.createPattern(img, repetition);
}



init();

// TODO: add physics https://github.com/shakiba/planck.js
* {
    box-sizing: border-box;
}

.toolbox {
    width: 100px;
    background-color: #535353;
}

.content {
    overflow: hidden;
    background-color: green;
    flex: 1;
}

.main {
    display: flex;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;

}
    <div class="main">
      <div class="toolbox">toolbox</div>
      <div id="canvas-container" class="content">
        <canvas id="canvas"></canvas>
      </div>
    </div>

有趣的是,它似乎在这个小提琴中工作得很好。但是当我在 Electron 下运行它时,this is what happens(gifv 链接)——(请忽略视频中光标有点偏离的事实——这只是我的屏幕录像机搞砸了)——但请注意最后一个点几下红线就乱了。

当我移动鼠标时,mousemove 处理程序中的console.log 正在触发,它正在记录正确的坐标。但是,我在 draw() 中使用的 mousePos 变量会固定在某个位置,然后不再更新。

我在每次鼠标移动事件时都更新同一个变量,我不明白这两个 console.logs 怎么会不同?


如果我这样记录,watch what happens

canvas.addEventListener('mousemove', ev => {
    let x = ev.clientX - canvas.offsetLeft;
    let y = ev.clientY - canvas.offsetTop;
    mousePos = {x,y};
    console.log('a',x,y);
})



function draw() {
    if(mousePos) {
        console.log('b', mousePos.x, mousePos.y);
    }

即使“a”不断更新,“b”也会停留在 {102, 570}。是同一个变量!

【问题讨论】:

    标签: javascript html5-canvas electron


    【解决方案1】:

    奇怪的行为,容易解决

    看到你的代码让我印象深刻的第一件事是 init 主函数被定义为 async 函数,但不包含等待。

    我不确定没有awaitasync 函数的预期行为,但问题似乎发生在同一时间段之后。

    这是一个有趣的问题,值得进一步研究。 spec (async function definitions) 中有很多要阅读的内容,快速浏览并没有显示任何明显的原因。

    轻松修复。

    修复很简单,从函数init 中删除async 令牌,一切正常。

    改变

    async function init() {
    

    function init() {
    

    示例

    const canvas = document.getElementById('canvas');
    const canvasContainer = document.getElementById('canvas-container');
    const ctx = canvas.getContext('2d');
    
    
    function resizeCanvas() {
        canvas.width = canvasContainer.clientWidth;
        canvas.height = canvasContainer.clientHeight;
    }
    
    
    
    function init() {
        window.addEventListener('resize', resizeCanvas)
        resizeCanvas();
    
    
    
        window.requestAnimationFrame(draw);
    
        let poly = [];
    
        canvas.addEventListener('click', ev => {
            let x = ev.clientX - canvas.offsetLeft;
            let y = ev.clientY - canvas.offsetTop;
            poly.push([x,y]);
        })
    
    
    
        window.addEventListener('keyup', ev => {
            if(ev.key === 'Escape') {
                poly.length = 0;
            }
        });
    
        let mousePos = null;
    
        canvas.addEventListener('mouseleave', ev => {
            mousePos = null;
        })
    
        canvas.addEventListener('mousemove', ev => {
            let x = ev.clientX - canvas.offsetLeft;
            let y = ev.clientY - canvas.offsetTop;
            mousePos = {x,y};
    
    
        })
    
    
    
        function draw() {
            // ctx.save();
    
            ctx.fillStyle = '#ADD5F8';
    
            ctx.fillRect(0, 0, canvas.width, canvas.height);
    
            ctx.fillStyle = '#C38F4C';
    
            if(poly.length >= 3) {
                ctx.beginPath();
                ctx.moveTo(...poly[0]);
                for(let i=1; i<poly.length; ++i) {
                    ctx.lineTo(...poly[i]);
                }
                ctx.closePath();
                ctx.fill();
            }
    
            if(poly.length && mousePos) {
                ctx.beginPath();
                ctx.moveTo(...poly[0]);
                for(let i=1; i<poly.length; ++i) {
                    ctx.lineTo(...poly[i]);
                }
                if(mousePos) {
         
                    ctx.lineTo(mousePos.x, mousePos.y);
                }
                ctx.strokeStyle = '#ff0000';
                ctx.stroke();
            }
    
    
            window.requestAnimationFrame(draw);
        }
    }
    
    function createImage(path) {
        return new Promise((resolve,reject) => {
            const img = new Image();
            img.onload = () => resolve(img);
            img.onerror = err => reject(err);
            img.src = path;
        })
    }
    
    async function createPattern(path, repetition='repeat') {
        // TODO: https://stackoverflow.com/a/21128933/65387
        const img = await createImage(path);
        return ctx.createPattern(img, repetition);
    }
    
    
    
    init();
    
    // TODO: add physics https://github.com/shakiba/planck.js
    * {
        box-sizing: border-box;
    }
    
    .toolbox {
        width: 100px;
        background-color: #535353;
    }
    
    .content {
        overflow: hidden;
        background-color: green;
        flex: 1;
    }
    
    .main {
        display: flex;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
    
    }
    <div class="main">
          <div id="info" class="toolbox">toolbox</div>
          <div id="canvas-container" class="content">
            <canvas id="canvas"></canvas>
          </div>
        </div>

    【讨论】:

    • 我删除了此代码示例的await...它正在等待加载图像/模式。我很确定没有等待或返回的异步函数会立即返回Promise&lt;undefined&gt;。或者也许在下一个滴答声中,但肯定不会导致这种情况。
    • @mpen init 在退出时解析(如果是异步的),所以函数没有问题。玩过它后,我发现如果你不给鼠标mousePos = {x,y}分配一个新对象,而只是分配它的属性(例如用const mousePos= {x:0,y:0}声明,在事件mousePos.x = x; mousePos.y = y;使用信号量来指示画布外的鼠标)然后它与init 一起使用async 它是丢失的新鼠标对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2021-07-31
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多