Javascript ImageData 绘图缩放不正确

标签 javascript jquery html5-canvas getimagedata drawingcontext

该程序的想法是获取 map 图像并在该 map 上覆盖黑色 Canvas 。然后用户将点击 Canvas 的某个部分,类似于喷漆工具,鼠标附近的像素将在 Canvas 上变得透明。因此,将显示 map (类似于 war 迷雾类型的特征)。当我在 Canvas 的左上角附近单击时,喷漆会按预期工作,但是当我在 Canvas 上进一步向右和向下单击时,变得透明的像素会向右和向下进一步移动......知道这里出了什么问题吗?这是代码:

// On document ready function.
$(document).ready(function() {
  canvas = document.getElementById("myImageDisplayerCanvas");
  drawingContext = canvas.getContext("2d");
  drawingContext.fillStyle = "#000000";
  drawingContext.fillRect(0, 0, 800, 554);
});

// Spray paint logic.
var _intervalId, // used to track the current interval ID
  _center, // the current center to spray
  density = 10,
  radius = 10,
  drawingCxt,
  leftClickPressed,
  drawingContext,
  canvas;

function getRandomOffset() {
  var randomAngle = Math.random() * 360;
  var randomRadius = Math.random() * radius;

  return {
    x: Math.cos(randomAngle) * randomRadius,
    y: Math.sin(randomAngle) * randomRadius
  };
}

this.startDrawing = function(position) {
  _center = position;
  leftClickPressed = true;
  // spray once every 10 milliseconds
  _intervalId = setInterval(this.spray, 10);
};

this.moveDrawing = function(position) {
  if (leftClickPressed) {
    clearInterval(_intervalId);
    _center = position;
    // spray once every 10 milliseconds
    _intervalId = setInterval(this.spray, 10);
  }
}

this.finishDrawing = function(position) {
  clearInterval(_intervalId);
  leftClickPressed = false;
};

this.spray = function() {
  var centerX = parseInt(_center.offsetX),
    centerY =
    parseInt(_center.offsetY),
    i;

  for (i = 0; i < density; i++) {
    var offset = getRandomOffset();
    var x = centerX + parseInt(offset.x) - 1,
      y = centerY +
      parseInt(offset.y) - 1;
    var dy = y * 800 * 4;
    var pos = dy + x * 4;
    var imageData = drawingContext.getImageData(0, 0, 800, 554);
    imageData.data[pos++] = 0;
    imageData.data[pos++] = 0;
    imageData.data[pos++] = 0;
    imageData.data[pos++] = 0;
    drawingContext.putImageData(imageData, 0, 0);
  }
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="myImageDisplayerDiv" style="position:relative; width:800px; height:554px">
  <img src="~/images/RedLarch.jpg" style="width:800px; height:554px; top: 0; left: 0; position: absolute; z-index: 0" />
  <canvas id="myImageDisplayerCanvas" onmousedown="startDrawing(event)" onmousemove="moveDrawing(event)" onmouseup="finishDrawing(event)" style="width:800px; height:554px; top: 0; left: 0; position: absolute; z-index: 1; opacity: 1; fill: black" />
</div>

最佳答案

设置 Canvas 分辨率。

喷雾偏移的原因是你没有设置 Canvas 分辨率。您通过 Canvas 元素的宽度和高度属性设置分辨率

<canvas id="canvas" width="800" height="554"></canvas>

设置样式宽度和高度设置 Canvas 显示大小而不是分辨率。如果您不设置 Canvas 分辨率,它默认为 300 x 150。

您的代码还有许多其他问题。

获取整个 Canvas 图像数据只是为了设置单个像素是一种矫枉过正的做法。只需创建一个像素 imageData 对象并将该像素放在需要的地方

使用requestAnimationFrame 与显示同步,切勿使用setIntervalsetTimeout,因为它们不会与显示硬件同步并且会导致您无穷无尽的问题。

创建一个鼠标事件函数来处理所有的鼠标事件,只记录鼠标状态。使用由 requestAnimationFrame 调用的主循环来处理绘图,从不从鼠标事件中绘制。

如果函数不是对象的一部分,则无需使用 this.functionName = function(){} 定义函数。

Trig 函数使用弧度而不是度数。 360 度的弧度是 2 * Math.PI

下面是使用上述注释快速重写的代码。

const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop); // start main loop when code below has run
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, 800, 554);

// create a pixel buffer for one pixel
const imageData = ctx.getImageData(0, 0, 1, 1);
const pixel32 = new Uint32Array(imageData.data.buffer);
pixel32[0] = 0;

// Spray paint logic.
const density = 10;
const  radius = 10;

// mouse handler
const mouse = {x : 0, y : 0, button : false};
function mouseEvents(e){
	const bounds = canvas.getBoundingClientRect();
	mouse.x = e.pageX - bounds.left - scrollX;
	mouse.y = e.pageY - bounds.top - scrollY;
	mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse"+name,mouseEvents));

function getRandomOffset() {
  const angle = Math.random() * Math.PI * 2;
  const rad = Math.random() * radius;
  return { x: Math.cos(angle) * rad, y: Math.sin(angle) * rad};
}

function spray(pos) {
  var i;
  for (i = 0; i < density; i++) {
    const offset = getRandomOffset();
    ctx.putImageData(imageData, pos.x + offset.x, pos.y + offset.y);
  }
}

// main loop called 60 times a second
function mainLoop(){
  if (mouse.button) { spray(mouse) }
  requestAnimationFrame(mainLoop);
}
<canvas id="canvas" width="800" height="554"></canvas>

关于Javascript ImageData 绘图缩放不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48091287/

相关文章:

jquery - 淡出内容而不是slideToggle 元素本身

HTML5 Canvas 的 Python 等效项

javascript - HTML5 Canvas 不会渲染从 canvas.toDataURI() 接收的数据

javascript - 在iPhone浏览器中上传照片时将默认设置切换为视频

javascript - 我怎样才能在vue js中传递字段Rating的值?

javascript - 模态转换显示问题

javascript - 使 Canvas 动画成为父 div 上的背景元素

javascript - 在另一个页面上克隆整个 div 容器

javascript - onUserLocationChange 更改 React Native map 区域

javascript - 通过 JavaScript 操作剪贴板