Canvas中lineTo()绘图函数的y坐标位置错误。

10
我试图使用ctx.lineTo()在画布上绘制一些矩形。它们被绘制出来了,但是y坐标从未正确。矩形变得太高,并且在y轴上的位置不正确。当我使用调试器逐步执行时,它显示在lineTo()方法中的y坐标是正确的,但是我创建了一个canvas.click事件来警报坐标(当我在左上角单击时,它警报(0,0),这是正确的)。点击事件显示,y坐标实际上并不在它所声明的lineTo()方法中将要绘制的位置。然而,x坐标始终是正确的。需要考虑的一件事是,我通过javascript向一个元素添加html来创建我的canvas,并在其中添加一个图像进行绘制。我重新调整矩形的坐标,使它们适当地放置在缩放到设备大小的图像尺寸的canvas上。下面是从canvas创建到使用lineTo()方法的全部代码。
function appendSection(theSection, list) {
    list.append('<label class="heading">' + theSection.description + '</label><br/><hr><br/>');
    if (theSection.picture) {
        appendPicture(list, theSection);
        var canvas = document.getElementById('assessmentImage');
        var ctx=canvas.getContext("2d");
         canvas.addEventListener("mousedown", relMouseCoords, false);

        var img=new Image();
            img.onload = function() {
                ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
            }
            img.src = "data:image/jpeg;base64,"+ theSection.picture;

        img.addEventListener('load', function() { 
            if(theSection.allHotSpots.length > 0) {
                for( var x = 0; x < theSection.allHotSpots.length; x++) {
                    appendHotSpot(theSection.allHotSpots[x], theSection.thePicture, ctx);
                }
            }

        }, false);

    }
    appendSectionQuestions(theSection, list);
    if (theSection.allSubSections) {
        for (var x = 0; x < theSection.allSubSections.length; x++) {
            var theSectionA = theSection.allSubSections[x];
            appendSection(theSectionA, list);
        }
    }
}

这里是appendPicture函数,它创建canvas标签并将其添加到一个元素中。
function appendPicture(list, theSection) {

        list.append('<div id="wrapper' + platform + '" style="width:100%; text-align:center">\
            <canvas class="assessmentImageSmall" style="width:100%;height:' + Math.round(theSection.thePicture.ySize * (document.getElementById('assessmentSectionForm' + platform).clientWidth / theSection.thePicture.xSize)) + 'px" id="assessmentImage' + platform + '" align="middle" ></canvas>\
            <!--<p style="color:#666;" id="imageInstruction">Tap image to enlarge.</p>-->\
            </div>');
        $("#wrapper").kendoTouch({
                                     tap: function (e) {
                                         switchImage();
                                     }
                                 });
}

这里是我绘制矩形的位置(在此函数中,我将矩形称为“热点”)。

function appendHotSpot(HotSpot, picture, ctx) {
    var imageWidth = document.getElementById('assessmentImage' + platform).clientWidth;

    var scale = imageWidth / picture.xSize;

    HotSpot.topLeft = [Math.round(HotSpot.topLeft[0] * scale), Math.round(HotSpot.topLeft[1] * scale)];
    HotSpot.bottomRight = [Math.round(HotSpot.bottomRight[0] * scale), Math.round(HotSpot.bottomRight[1] * scale)];

    var rect = {x1: HotSpot.topLeft[0], y1: HotSpot.topLeft[1], x2: HotSpot.bottomRight[0], y2: HotSpot.bottomRight[1]};

    ctx.strokeStyle="red";
    ctx.beginPath();
    ctx.moveTo(rect.x1, rect.y1);
    ctx.lineTo(rect.x2, rect.y1);
    ctx.lineTo(rect.x2, rect.y2);
    ctx.lineTo(rect.x1, rect.y2);
    ctx.lineTo(rect.x1, rect.y1);
    ctx.stroke();
}

请创建一个 jsFiddle。 - Steve Wellens
2个回答

13

Canvas 的宽度和高度与其 CSS 宽度和高度不同!

这意味着 canvas 会被拉伸以对齐 CSS 大小。这对于缩放是有好处的,但可能会导致像您使用 width: 100% 时遇到的问题。


两种解决方案(取决于您需要什么):

  • 读取 canvas 的 DOM 元素大小并将其应用于 canvas 本身(请参见下面示例中的第四个画布)
  • 根据 canvas 的实际大小修改其 CSS 样式(请参见下面示例中的第五个画布)

简单示例:

function buildCanvas(w, h, sizeFromDOM, changeCSS, looksFine) {
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');
  document.body.appendChild(canvas);
  canvas.style.borderColor = looksFine ? "green" : "red";

  if (sizeFromDOM) {
    // read its size from the DOM
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
  } else {
    // or simply apply what was given
    canvas.width = w;
    canvas.height = h;
  }
  
  // change CSS styles if needed
  if (changeCSS) {
    canvas.style.width = canvas.width + 'px';
    canvas.style.height = canvas.height + 'px';
  }
  
  // draw the same 80x80 square on each
  ctx.strokeStyle = looksFine ? "green" : "red";
  ctx.beginPath();
  ctx.moveTo(10, 10);
  ctx.lineTo(90, 10);
  ctx.lineTo(90, 90);
  ctx.lineTo(10, 90);
  ctx.lineTo(10, 10);
  ctx.stroke();
}

buildCanvas(200, 200, false, false, true); // this canvas is fine as it matches the CSS sizes
buildCanvas(300, 200); // this canvas is stretched horizontally
buildCanvas(200, 300); // this canvas is stretched vertically
buildCanvas(200, 300, true, false, true); // let's fix this one
buildCanvas(300, 200, false, true, true); // this one too, but by changing its CSS
canvas {
  width: 200px;
  height: 200px;
  border: 1px solid #aaa;
  margin: 4px;
}


是的,这正在发生,我已经指定了不同的CSS大小。谢谢。你知道解决方案吗? - btf
不客气。嗯,解决方案是获取画布DOM元素的大小并将其应用于画布本身。例如:canvas.width = canvas.offsetWidth。使用修复后的(第4个)画布更新了我的答案。 - Shomz
另一种解决方案是读取画布的大小并更改其CSS样式(根据您的需求),例如:canvas.style.width = canvas.width + 'px'; 请参见我的示例中的第5个画布。 - Shomz
非常好的答案。我使用了你的示例中第5个画布的方法,效果很棒。谢谢。 - btf

3
这是一个不错的技巧,可以将所有canvas元素的高度和宽度设置为与其CSS设置相同。请看下方代码:

var canvases = document.getElementsByTagName("canvas");
for(var i=0; i<canvases.length; i++)
{
  canvas = canvases[i];
  canvas.width = canvas.offsetWidth;
  canvas.height = canvas.offsetHeight;
}

现在你可以通过CSS设置画布的尺寸!(感谢@Shomz的回答,否则我不会想到这个方法)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接