Canvas lineTo() drawing y coordinate in wrong place

耗尽温柔 提交于 2020-01-12 17:23:05

问题


I'm trying to draw some rectangles on a canvas using ctx.lineTo(). They get drawn but the y coordinate is never right. The rectangles become too tall and on the wrong place on the y axis. When I step through with the debugger it shows the y coordinates within the lineTo() methods as being correct, but I made a canvas.click event to alert the coordinates (which are correct as I click in the top left and it alerts (0,0)). The click event shows that the y coordinate is not actually where it states it will be drawn in the lineTo() method. The x coordinate is however always correct. One thing to be considered is I create my canvas by appending html to an element with javascript, and I add an image to it that I draw on. I rescale the coordinates of the rectangles so they are appropriately place on the canvas which is scaled to the image size that works for the size of the device. Here is all my code from canvas creation to using the lineTo() method.

Canvas gets created in early stages of this method (in appendPicture()):

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);
        }
    }
}

Here is appendPicture which creates the canvas html and appends it to an element.

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();
                                     }
                                 });
}

Here is where I draw the rectangle (I call rectangles hotspots in this function)

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();
}

回答1:


Canvas' width and height are different from its CSS width and height!

This means that the canvas gets stretched to align to CSS sizes. This is good for scaling, but can result in issues like the ones you're having with width: 100%.


Two solutions (depending on what you need):

  • read the canvas' DOM element size and apply it to the canvas itself (see the 4th canvas in the example below)
  • modify its CSS styles based on the canvas' actual size (see the 5th canvas below)

Simple example:

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;
}



回答2:


Here's a nice little kludge that will set all canvas elements' heights and widths to equal their CSS settings.

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

Now you can continue to set canvas dimensions by CSS!

(I wouldn't have figured this out without @Shomz' answer.)



来源:https://stackoverflow.com/questions/28142351/canvas-lineto-drawing-y-coordinate-in-wrong-place

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!