Canvas lineTo () drawing the y coordinate in the wrong place

I am trying to draw some rectangles on a canvas using ctx.lineTo (). They are drawn, but the y coordinate is never correct. Rectangles get too tall and out of place on the y axis. When I go to the debugger, it shows the y coordinates in the lineTo () methods as correct, but I did a canvas.click event to warn the coordinates (which are correct when I click in the upper left corner and it warns (0, 0)) . A click event indicates that the y coordinate does not actually indicate that it will be drawn in the lineTo () method. However, the x coordinate is always correct. One thing to consider is to create your canvas by adding html to the javascript element and add the image to which I am drawing. I scale the coordinates of the rectangles so that they are properly placed on the canvas, which scales to the size of the image, which works for the size of the device. Here is all my code from creating a canvas using the lineTo () method.

The canvas is created in the 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 the appendPicture that creates the html canvas and adds it to the 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(); } }); } 

This is where I draw the rectangle (I call the hotspots of the rectangles 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(); } 
+5
source share
2 answers

The width and height of the canvas are different from the width and height of the CSS!

This means the canvas is stretched to fit CSS. This is useful for scaling, but can lead to problems like the ones you have: 100%.


Two solutions (depending on what you need):

  • read the size of the canvas DOM element and apply it to the canvas itself (see 4th canvas in the example below)
  • change your CSS styles based on actual canvas size (see fifth canvas below)

A 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 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; } 
+6
source

Here's a nice little kludge that will set all the heights and widths of the canvas elements to fit 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 sizes using CSS!

(I would not understand this without @Shomz's answer.)

+1
source

Source: https://habr.com/ru/post/1211893/


All Articles