Search code examples
javascripttexthtml5-canvascurve

Problem with Drawing Text on an Arc in Canvas using Javascript


I would like to draw "user-supplied text" on an arc shape in HTML canvas using Javascript. This was the closest example I've seen for a soultion: Create an arc text using canvas

However in my code, I keep getting a "Uncaught TypeError: Cannot read property 'getContext' of null" Where am I going wrong?

HTML

<!DOCTYPE HTML>
<html>
<head>
  <style>
    body {
      margin: 0px;
      padding: 0px;
    }
#canvas{
  display:block;
  margin:0 auto;
}
  </style>
<script src="textOnPath3.js"></script>
</head>
<body>
<canvas id="myCanvas" width="900" height="400" style="border:1px solid #ff0000;"></canvas>
</body>
</html>

JAVASCRIPT

 window.addEventListener("load", eventWindowLoaded, false);

      var canvas = document.getElementById('myCanvas'), 
        context = canvas.getContext('2d'),
        centerX = canvas.width / 2,
        centerY = canvas.height - 30,
        angle = Math.PI * 0.8,
        radius = 150;

      context.font = '30pt helvetica';
      context.textAlign = 'center';
      context.fillStyle = 'red';
      context.strokeStyle = 'blue';
      context.lineWidth = 4;
      drawTextAlongArc(context, 'Arc Canvas Text', centerX, centerY, radius, angle);

      // draw circle underneath text
      context.arc(centerX, centerY, radius - 10, 0, 2 * Math.PI, false);
      context.stroke();

function eventWindowLoaded () {
    drawTextAlongArc();
}
function drawTextAlongArc(context, str, centerX, centerY, radius, angle) {
        var len = str.length, s;
        context.save();
        context.translate(centerX, centerY);
        context.rotate(-1 * angle / 2);
        context.rotate(-1 * (angle / len) / 2);
        for(var n = 0; n < len; n++) {
          context.rotate(angle / len);
          context.save();
          context.translate(0, -1 * radius);
          s = str[n];
          context.fillText(s, 0, 0);
          context.restore();
        }
        context.restore();
}

Solution

  • The problem is though you've added an event listener to check if the page finished loading, it will just call the function eventWindowLoaded.

    That means all other commands right after this line

    window.addEventListener("load", eventWindowLoaded, false);
    

    will get called no matter if it's loaded or not.

    So as soon as it reaches

    context = canvas.getContext('2d')
    

    it will fail with the error you got. The html canvas element is not yet available so the value of canvas will be undefined.

    To fix this wrap everything inside the eventWindowLoaded function like:

     window.addEventListener("load", eventWindowLoaded, false);
    
     function eventWindowLoaded() {
       var canvas = document.getElementById('myCanvas');
       context = canvas.getContext('2d');
       centerX = canvas.width / 2;
       centerY = canvas.height - 30;
       angle = Math.PI * 0.8;
       radius = 150;
    
       context.font = '30pt helvetica';
       context.textAlign = 'center';
       context.fillStyle = 'red';
       context.strokeStyle = 'blue';
       context.lineWidth = 4;
       drawTextAlongArc(context, 'Arc Canvas Text', centerX, centerY, radius, angle);
    
       // draw circle underneath text
       context.arc(centerX, centerY, radius - 10, 0, 2 * Math.PI, false);
       context.stroke();
    
       drawTextAlongArc();
     }