I wanted to add JavaScript to a WordPress post, in order to animate on a canvas
element.
Canvas
I added the canvas
element in the Code Editor, giving it the unique id
myCanvas
. The width and height of the element are measured in pixels.
1 2 3 |
<!-- wp:paragraph --> <p><canvas id="myCanvas" width="747" height="100" style="border: 1px solid #000000"></canvas></p> <!-- /wp:paragraph --> |
JavaScript
The JavaScript did not need to export any identifiers, and so could be put within a self-invoking anonymous function ((function() {...})();
).
Each ball is a value (an object) in array balls
. The function ballsMove
is called every 10 milliseconds, through the function setInterval
. Each ball is moved, in turn. If it intersects a wall (isWall()
), or another ball (isBall()
), it bounces back and its velocity is affected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
(function () { var canvas = document.getElementById("myCanvas"); var width = canvas.width; var height = canvas.height; var ctx = canvas.getContext("2d"); var balls = []; var n = 50; var r = 5; var d = 2 * r; var d2 = d * d; var pi2 = Math.PI * 2; var angle; var ball; for (var i = 0; i < n; i++) { do { angle = Math.random() * pi2; ball = { x: Math.random() * (width - d) + r, y: Math.random() * (height - d) + r, xm: Math.cos(angle) * 2, ym: Math.sin(angle) * 2, i: i === 0 }; } while (collision(ball)); balls.push(ball); } setInterval(ballsMove, 10); function collision(newBall) { var count = balls.length; var isCollision = false; if (count === 0) { return isCollision; } for (var i = 0; i < count; i++) { if (overlap(balls[i], newBall)) { isCollision = true; break; } } return isCollision; } function overlap(ball1, ball2) { var dx = (ball1.x - ball2.x); var dy = (ball1.y - ball2.y); return (dx * dx + dy * dy < d2); } function ballsMove() { balls.forEach(ballMove); ctx.clearRect(0, 0, width, height); balls.forEach(ballDraw); } function ballMove(ball, i) { ball.x += ball.xm; ball.y += ball.ym; if (!isWall(ball)) { isBall(ball, i); } } function isWall(ball) { var bounce = false; var xm = ball.xm; var ym = ball.ym; if (ball.x < r || ball.x > width - r) { bounce = true; xm = -xm; } if (ball.y < r || ball.y > height - r) { bounce = true; ym = -ym; } if (bounce) { ballBack(ball); ball.xm = xm; ball.ym = ym; } return bounce; } function isBall(balli, i) { var ballj; var xm; var ym; var bounce = false; for (var j = 0; j < n; j++) { if (j != i) { ballj = balls[j]; if (overlap(balli, ballj)) { ballBack(balli); xm = balli.xm; ym = balli.ym; balli.xm = ballj.xm; balli.ym = ballj.ym; ballj.xm = xm; ballj.ym = ym; bounce = true; break; } } } return bounce; } function ballBack(ball) { ball.x -= ball.xm; ball.y -= ball.ym; } function ballDraw(ball) { ctx.fillStyle = ball.i ? "#FF0000" : "#00FF00"; ctx.beginPath(); ctx.arc(ball.x, ball.y, r, 0, pi2); ctx.fill(); ctx.stroke(); } })(); |
I placed the JavaScript file (named post808.js
, after the post id) in a js
folder of the theme.
PHP
The theme is a child theme. I used the Child Theme Configurator plugin to add code to its functions.php
file. The code adds an action to the wp_head
hook. The action uses the is_single()
function, which tests whether the query is for an existing single post.
The defer
attribute of the script
element is necessary to ensure that the page has been parsed before the script searches for the element with id
myCanvas
.
1 2 3 4 5 6 7 8 |
function wp_post808_hook_javascript() { if (is_single ('808')) { ?> <script defer="defer" src="https://pilgrem.com/wp-content/themes/slightly-child/js/post808.js"></script> <?php } } add_action('wp_head', 'wp_post808_hook_javascript'); |