【问题标题】:HTML Canvas - background eraser not working on a single clickHTML Canvas - 背景橡皮擦无法单击一次
【发布时间】:2020-02-04 13:43:12
【问题描述】:

我正在使用 html5 画布和 angularJS 开发一个背景移除器应用程序。我正在堆叠两个画布并使用与橡皮擦大小相对应的自定义光标从顶部删除像素。我有一个非常奇怪的错误,它只允许我在快速移动鼠标时删除前景,单击和缓慢的鼠标移动不会影响画布。我怀疑角度偶数侦听器存在问题,因为我在 vscode 中使用 liveServer 和标准 JS 事件侦听器 canvas.addEventListener('mousemove', erase); 运行的代码版本相同。对此的任何帮助将不胜感激。

我正在编写代码笔以更好地说明问题。

标记:

<div class="cursor" ng-mousemove="erase($event)"
     ng-mousedown="startPosition($event)"
     ng-mouseup="finishedPosition($event)"><!-- -->
    <!--ng-click="cursorMove($event)"-->
    <span class="innerCursor"></span>
</div>

<div class="canvas-container" ng-init="init();">
    <canvas id="canvas" style="z-index: 2;" ng-mousemove="erase($event);"
            ng-mousedown="startPosition($event)"
            ng-mouseup="finishedPosition($event)"></canvas>
    <canvas id="bgCanvas" style="z-index: 1;"></canvas>
</div>

JS:

//Gets real mouse position in canvas
function getMousePos(canvas, e) {
    var rect = canvas.getBoundingClientRect(), // abs. size of element
        scaleX = canvas.width / rect.width,    // relationship bitmap vs. element for X
        scaleY = canvas.height / rect.height;  // relationship bitmap vs. element for Y

    return {
        x: (e.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
        y: (e.clientY - rect.top) * scaleY     // been adjusted to be relative to element
    }
}

//Controls the movement of the custom cursor 
$scope.cursorMove = function (x, y) {
    var cursor = document.querySelector('.cursor');
    cursor.setAttribute('style', 'width: ' + $scope.options.brushSize + 'px; height: ' + $scope.options.brushSize + 'px; top: ' + y + 'px; left: ' + x + 'px; transform : translate(-' + 50 + '%, -' + 50 + '%)' + ';');
}

$scope.init = function () {
    //Foreground
    $scope.canvas = document.querySelector('#canvas');
    $scope.ctx = canvas.getContext('2d');
    //Background
    $scope.bgCanvas = document.querySelector('#bgCanvas');
    $scope.ctxBg = bgCanvas.getContext('2d');

    $scope.ctx.canvas.height = 600;
    $scope.ctx.canvas.width = 900;

    $scope.drawAll();
}

//Display all elements
$scope.drawAll = function () {
    $scope.drawForeground();
    $scope.drawBackground();
}

$scope.drawForeground = function () {
    console.log('foreground');
    var url = $scope.personalisationOptions.noBackgroundImage;
    //var url = 'img link';
    var img1 = new Image();
    img1.src = url + '?' + new Date().getTime();
    img1.setAttribute('crossOrigin', '');
    img1.onload = function () {
        $scope.ctx.drawImage(img1, 0, 0, $scope.ctx.canvas.clientWidth, $scope.ctx.canvas.clientHeight);
    }
}

$scope.drawBackground = function () {
    console.log('background');
    var img2 = new Image();
    img2.src = 'img link';
    img2.onload = function () {
        $scope.ctxBg.drawImage(img2, 0, 0, $scope.ctx.canvas.clientWidth, $scope.ctx.canvas.clientHeight);
    }
}

//Erasing functionality
$scope.erasing = false;

$scope.erase = function (e) {

    var pos = getMousePos(canvas, e);
    $scope.cursorMove(pos.x, pos.y);

    if (!$scope.erasing) return;

    if (!$scope.pendingSnapshot) {
        $scope.pendingSnapshot = $scope.ctx.getImageData(0, 0, window.innerWidth, window.innerHeight);
    }

    if ($scope.options.isCircle) {
        console.log('B');
        // circular eraser
        $scope.ctx.save();
        $scope.ctx.beginPath();
        $scope.ctx.arc(e.offsetX, e.offsetY, $scope.options.brushSize / 2, 0, 2 * Math.PI, true);
        $scope.ctx.clip();
        //eraser with new coordinates pos.x / pos.y
        $scope.ctx.clearRect(pos.x - $scope.options.brushSize, pos.y - $scope.options.brushSize, $scope.options.brushSize * 2, $scope.options.brushSize * 2);
        console.log(pos.x, pos.y - $scope.options.brushSize);
        $scope.ctx.restore();
    } else {
        // square eraser
        $scope.ctx.beginPath();
        $scope.ctx.clearRect(e.offsetX, e.offsetY, $scope.options.brushSize, $scope.options.brushSize);
    }
}

$scope.startPosition = function (e) {
    $scope.erasing = true;
    $scope.erase(e);
    console.log('mouse down');
}

$scope.finishedPosition = function () {
    $scope.erasing = false;
    console.log('mouse up');
    $scope.ctx.beginPath();
    $scope.imageSnapshot = $scope.pendingSnapshot;

    //limit clickHistory to 5
    if ($scope.clickHistory.length > 4) {
        $scope.clickHistory.shift();
    }

    $scope.clickHistory.push($scope.pendingSnapshot);
    $scope.pendingSnapshot = null;
}

【问题讨论】:

标签: javascript html angularjs canvas


【解决方案1】:

原来是我的自定义光标导致了这个问题。光标 div 位于画布前面,并且阻止擦除功能正常工作,因为它从未访问过画布。这就解释了为什么只有当我快速移动鼠标时擦除才有效。实际光标领先于自定义光标。

我现在正在使用这篇文章中的 svg 光标解决方案:Dynamically change SVG cursor

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-14
    • 1970-01-01
    • 2011-03-27
    • 2014-09-11
    • 2011-04-16
    • 2014-11-12
    • 2013-10-19
    • 2012-09-30
    相关资源
    最近更新 更多