user6778257 user6778257 - 3 months ago 22
HTML Question

context.beginPath() is not a function - why?

I'm trying to build an analogue clock SP feature, but before anything else, I've put it in an HTML file to provide proof of concept.

In an HTML file, separate from SharePoint, the code runs perfectly fine, no problem (in IE, Chrome and Firefox).

However, if I point a Content Editor web part to this file, the canvas draws but the

setInterval
doesn't fire because I get this:


Uncaught TypeError:
ctx.beginPath
is not a function


How do I resolve that?

Code (edited):



<canvas id="abcdef" width="400" height="400"></canvas>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

<script>

(function() {

var canvas = document.getElementById("abcdef");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;

ctx.translate(radius, radius);
radius = radius * 0.90;
drawClock(ctx);
setInterval(drawClock, 1000);

function drawClock(context) {

drawFace(context);
drawNumbers(context);
drawTime(context);
}

function drawFace(ctx) {

var grad;

console.info(ctx);

ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fillStyle = "lightgrey";
ctx.fill()

grad = ctx.createRadialGradient(0, 0, radius * 0.95, 0, 0, radius * 1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius * 0.1;
ctx.stroke();

ctx.beginPath();
ctx.arc(0, 0, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = 'black';
ctx.fill();
}

function drawNumbers(ctx) {

var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (num = 1; num < 13; num++) {
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius * 0.85);
ctx.rotate(-ang);
}
}

function drawTime(ctx) {

var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();

//hour
hour = hour % 12;
hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60));
drawHand(hour, radius * 0.5, radius * 0.07, "grey");

//minute
minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60));
drawHand(minute, radius * 0.8, radius * 0.07, "black");

// second
second = (second * Math.PI / 30);
drawHand(second, radius * 0.9, radius * 0.02, "red");
}

function drawHand(pos, length, width, colour) {

ctx.beginPath();
ctx.lineWidth = width;
ctx.lineCap = "round";
ctx.strokeStyle = colour;
ctx.moveTo(0, 0);
ctx.rotate(pos);
ctx.lineTo(0, -length);
ctx.stroke();
ctx.rotate(-pos);
}

}());

</script>

Answer

I didn't explain, well try this:

(function() {

    var canvas = document.getElementById("abcdef");
    var ctx = canvas.getContext("2d");
    var radius = canvas.height / 2;

    ctx.translate(radius, radius);
    radius = radius * 0.90;

    setInterval(function(){
      drawClock(ctx);
    }, 1000);

    function drawClock(context) {

        drawFace(context);
        drawNumbers(context);
        drawTime(context);
    }

  /* the rest */

 }());

because setInterval(drawClock, 1000); this line invoces the drawClock function every second with like this drawClock().

But if you pass this function to the setInterval:

    setInterval(function(){
      drawClock(ctx);
    }, 1000);

the drawClock function will be called with the correct context, due to javascript closure "feature".(here some details to Closures)

Update: this works on my system, but if your code of before stopped working on sharepoint, i can't garantee it, nevertheless the Immediately invoked function expressions (IIFE) should solve possible conflicts.