Home > database >  Why is the Canvases image squished when used `.toDataURL()`?
Why is the Canvases image squished when used `.toDataURL()`?

Time:12-20

I want to make the canvases PNG file, when exported, to be not squished ( Original size: Width: 480 pixels, height: 360 pixels. ) and plus, have the blue background color ( Color: #85c9ff ) . Source:

HTML:

<!DOCTYPE html>
<html>
  <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>Flippy in JavaScript! - Replit</title>
      <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body onl oad="startGame()">
      <canvas id="flippyGoesHere"></canvas>
      <center>
          <button onm ousedown="moveup()" onm ouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>
      <div>
        <button onm ousedown="moveleft()" onm ouseup="clearmove()" ontouchstart="moveleft()">LEFT</button>
        <button onm ousedown="moveright()" onm ouseup="clearmove()" ontouchstart="moveright()">RIGHT</button>
        <br>
        <br>
      </div>
      <button onm ousedown="movedown()" onm ouseup="clearmove()" ontouchstart="movedown()">DOWN</button>
      <br>
      <br>
      <button onclick="exportAsPng()">EXPORT AS IMAGE</button>
      <br>
      <br>
    </center>
    <a href="" download="canvas.png" id="imgLink"></a>
    <script src="script.js"></script>
  </body>
</html>

JS:

var myGamePiece;
var imgLink = document.getElementById("imgLink")

function startGame() {
  myGamePiece = new component(20, 10, "/flippy.svg", 140, 70, "image");
  myGameArea.start();
  myGameArea.context.fillStyle = "#85c9ff"
  myGameArea.context.fillRect(0, 0, myGameArea.canvas.width, myGameArea.canvas.height)
}

var myGameArea = {
  canvas: document.getElementById("flippyGoesHere"),
  start: function () {
    this.context = this.canvas.getContext("2d");
    document.body.insertBefore(this.canvas, document.body.childNodes[0]);
    this.frameNo = 0;
    this.interval = setInterval(updateGameArea, 20);
  },
  clear: function () {
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  },
  stop: function () {
    clearInterval(this.interval);
  }
}

function component(width, height, color, x, y, type) {
  this.type = type;
  if (type == "image") {
    this.image = new Image();
    this.image.src = color;
  }
  this.width = width;
  this.height = height;
  this.speedX = 0;
  this.speedY = 0;
  this.x = x;
  this.y = y;
  this.update = function () {
    ctx = myGameArea.context;
    if (type == "image") {
      ctx.drawImage(this.image,
        this.x,
        this.y,
        this.width, this.height);
    } else {
      ctx.fillStyle = color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
    }
  }
  this.newPos = function () {
    this.x  = this.speedX;
    this.y  = this.speedY;
  }
}

function updateGameArea() {
  myGameArea.clear();
  myGamePiece.newPos();
  myGamePiece.update();
}

function moveup() {
  myGamePiece.speedY = -1;
}

function movedown() {
  myGamePiece.speedY = 1;
}

function moveleft() {
  myGamePiece.speedX = -1;
}

function moveright() {
  myGamePiece.speedX = 1;
}

function clearmove() {
  myGamePiece.speedX = 0;
  myGamePiece.speedY = 0;
}

function exportAsPng() {
  imgLink.setAttribute("href", myGameArea.canvas.toDataURL())
  imgLink.click()
}

And CSS, I don't know why:

body {
  margin: 0;
}

a#imgLink {
  display: none;
}

a#imgLink::before {
  content: attr(href);
}

canvas#flippyGoesHere {
  width: 480px;
  height: 360px;
  background-color: #85c9ff;
}

button { /* For all buttons! */
  cursor: pointer;
}

Demo is here!

Here's the resulted image, when the turtle is not moving:

Aw man!

CodePudding user response:

You can see that the width and height of the canvas is not what you specified in CSS: myGameArea.canvas.width is 300 and myGameArea.canvas.height is 150. The problem is that the actual size of the canvas is different from its display size.

Setting the canvas size in HTML reveals that the exported image is the same as the canvas.

<canvas id="flippyGoesHere" width="480" height="360"></canvas>

The issue with the background color also lies in the CSS. Specifying the background color in CSS only displays that color, not rendering it in the canvas.

Filling the canvas with the background color (and for good practice, removing the background-color in CSS) should solve the problem.

this.update = function () {
    ctx = myGameArea.context;
    ctx.fillStyle = "#85c9ff";
    ctx.fillRect(0, 0, width, height);
    // ...
}

CodePudding user response:

Building on KeroppiMomo's answer ...

Use the myGameArea.clear() method to colour the background too

var myGameArea = {
...  
   clear: function () {
       myGameArea.context.fillStyle = "#85c9ff"
       myGameArea.context.fillRect(0, 0, myGameArea.canvas.width, 
   myGameArea.canvas.height)
   },

Get rid of all of the css for canvas#flippyGoesHere, that is just confusing things as it's affecting the display of the canvas.

You can set the canvas size in the html like KeroppiMomo suggested, or you can set it in the javascript (perhaps in your startGame() function):

  myGameArea.canvas.height = 500
  myGameArea.canvas.width = 500
  • Related