preface
Since I have met canvas repeatedly in the interview process, and I only know and learn the theoretical knowledge of Canvas, I will make a whole demo!
The corresponding files have been organized and uploaded to their own warehouse.
Gitee warehouse
Making the warehouse
followImooc seriesStudy summary, if there is not clear place, also suggest with me from zero to watch learning oh
Canvas based
Create a Canvas
HTML tags
<canvas id="canvas" width="1024" height="768" style="border: 1px solid #aaa; display: block; margin: auto auto">
<! -- Compatible error reduction -->The current browser does not support Canvas. Please change your browser and try again</canvas>
Copy the code
Block-level elements, by default, are 350px wide and 150px high
W3C specifies that width and height should be used to specify the size (canvas size and pixel size)
Javascript
const canvas = document.getElementById('canvas')
// Draw context 2D drawing
const context = canvas.getContext('2d')
Copy the code
Canvas to draw
Draw a straight line
// State Settings - with top left corner as vertex (0, 0)
context.moveTo(100.100) // The nib moves
context.lineTo(700.700) // Move the brush to this point
// Common attributes
/ / line
context.lineWidth = 5 / / line
context.strokeStyle = '# 005588' / / thread color
context.stroke() // Start drawing
Copy the code
Draw a polygon
/ / triangle
context.moveTo(100.100) // The nib moves
context.lineTo(700.700) // Move the brush to this point
context.lineTo(100.700) // Move the brush to this point
context.lineTo(100.100) // Move the brush to this point
// Common attributes
/ / line
context.lineWidth = 5 / / line
context.strokeStyle = '# 005588' / / thread color
/ / fill
context.fillStyle = 'rgb(2, 100, 30)' // Fill the color
context.fill() / / fill
context.stroke() // Start drawing
Copy the code
Draw a tangram
// Tangram line data
const tanGram = [
{p: [{x: 0.y: 0}, {x: 800.y: 0}, {x: 400.y: 400}].color: '#caff67'},
{p: [{x: 0.y: 0}, {x: 400.y: 400}, {x: 0.y: 800}].color: '#67beef'},
{p: [{x: 800.y: 0}, {x: 800.y: 400}, {x: 600.y: 600}, {x: 600.y:200}].color: '#ef3d61'},
{p: [{x: 600.y: 200}s, {x: 600.y: 600}, {x: 400.y: 400}].color: '#f9f51a'},
{p: [{x: 400.y: 400}, {x: 600.y: 600}, {x: 400.y: 800}, {x: 200.y: 600}].color: '#a594c0'},
{p: [{x: 200.y: 600}, {x: 400.y: 800}, {x: 0.y: 800}].color: '#fa8ecc'},
{p: [{x: 800.y: 400}, {x: 800.y: 800}, {x: 400.y: 800}].color: '#f6ca29'},]window.onload = function() {
/ / jigsaw puzzle
const canvas = document.getElementById('canvas')
// Draw context 2D drawing
const context = canvas.getContext('2d')
const len = tanGram.length
// Draw each polygon
for (let i = 0; i < len; i++) {
draw(tanGram[i], context)
}
}
function draw(piece, cxt) {
// Start drawing
cxt.beginPath();
cxt.moveTo(piece.p[0].x, piece.p[0].y)
const len = piece.p.length
for (let i = 1; i < len; i++) {
cxt.lineTo(piece.p[i].x, piece.p[i].y)
}
// Finish drawing
cxt.closePath()
cxt.fillStyle = piece.color
cxt.fill()
}
Copy the code
Draw arcs and circles
The method attributes
constext.arc(
centerx, centery, radius, // The center of the circle origin coordinates and the radius values
startingAngle, endingAngle, // The range of radians
anticlockwise = false // Whether to turn clockwise (optional) - Default false to turn clockwise
)
Copy the code
arc
context.lineWidth = 5
context.strokeStyle = '# 005588'
context.arc(300.300.200.0.1.5 + Math.PI)
context.stroke()
Copy the code
Continuous arc
context.lineWidth = 5
context.strokeStyle = '# 005588'
// Discontinuous arc
for (let i = 0; i < 10; i++) {
context.beginPath()
context.arc(50 + i*100.60.40.0.2*Math.PI*(i+1) /10)
context.closePath()
context.stroke()
}
/ / continuous arc
for (let i = 0; i < 10; i++) {
context.beginPath()
context.arc(50 + i*100.180.40.0.2*Math.PI*(i+1) /10)
context.stroke()
}
Copy the code
round
context.lineWidth = 5
context.strokeStyle = '# 005588'
for (let i = 0; i < 10; i++) {
context.beginPath()
context.arc(50 + i*100.60.40.0.2*Math.PI*(i+1) /10)
context.closePath()
context.fill() / / fill
}
for (let i = 0; i < 10; i++) {
context.beginPath()
context.arc(50 + i*100.180.40.0.2*Math.PI*(i+1) /10)
context.fill() / / fill
}
Copy the code
Realized electronic clock
Drawing electronic clock
The directory structure
Digin.js // A two-dimensional lattice that stores numbers
Countdown.js // Concrete logic
Index.html // The specific page
2d lattice – digin.js
Because there’s a lot of data, let’s take a little example
// indicates that 0,1 indicates that the circle needs to be drawn[[0.0.1.1.1.0.0],
[0.1.1.0.1.1.0],
[1.1.0.0.0.1.1],
[1.1.0.0.0.1.1],
[1.1.0.0.0.1.1],
[1.1.0.0.0.1.1],
[1.1.0.0.0.1.1],
[1.1.0.0.0.1.1],
[0.1.1.0.1.1.0],
[0.0.1.1.1.0.0]]Copy the code
Concrete logic – Countdown.js
Initialize the
/ / constant
const WINDOW_WIDTH = 1024;
const WINDOW_HEIGHT = 768;
const RADIUS = 8;
const MARGIN_TOP = 60;
const MARGIN_LEFT = 30;
window.onload = function(){
// Initialize the canvas
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
canvas.width = WINDOW_WIDTH;
canvas.height = WINDOW_HEIGHT;
// Draw method
render( context )
}
Copy the code
Draw the dot
// Draw the dots
function renderDigit( x , y , num , cxt ){
cxt.fillStyle = "RGB (0102153)";
for(let i = 0 ; i < digit[num].length ; i ++ )
for(let j = 0 ; j < digit[num][i].length ; j ++ )
if( digit[num][i][j] == 1 ){
cxt.beginPath();
// The center of the (I, j) circle:
// j*2*(R+1) => JTH column box
// x: x+j*2*(R+1)+(R+1)
// y: y+i*2*(R+1)+(R+1)
cxt.arc( x+j*2*(RADIUS+1)+(RADIUS+1) , y+i*2*(RADIUS+1)+(RADIUS+1) , RADIUS , 0 , 2*Math.PI )
cxt.closePath()
cxt.fill()
}
}
Copy the code
Draw a number dot
// Draw each dot of the number
function render( cxt ){
let hours = 12
let minutes = 34
let seconds = 56
/ / 1
renderDigit( MARGIN_LEFT , MARGIN_TOP , parseInt(hours/10) , cxt )
/ / 2
renderDigit( MARGIN_LEFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(hours%10) , cxt )
/ / :
renderDigit( MARGIN_LEFT + 30*(RADIUS + 1) , MARGIN_TOP , 10 , cxt )
/ / 3
renderDigit( MARGIN_LEFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(minutes/10) , cxt);
/ / 4
renderDigit( MARGIN_LEFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(minutes%10) , cxt);
/ / :
renderDigit( MARGIN_LEFT + 69*(RADIUS+1) , MARGIN_TOP , 10 , cxt);
/ / 5
renderDigit( MARGIN_LEFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(seconds/10) , cxt);
/ / 6
renderDigit( MARGIN_LEFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(seconds%10) , cxt);
}
Copy the code
Time to calculate
Initialize the
// Remember to dynamically change your deadlines
const endTime = new Date(2021.3.7.0.0.0);
let curShowTimeSeconds = 0
Copy the code
draw
window.onload = function(){
// Initialize the canvas
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
canvas.width = WINDOW_WIDTH;
canvas.height = WINDOW_HEIGHT;
curShowTimeSeconds = getCurrentShowTimeSeconds()
render( context )
}
Copy the code
Get time number
// Get the current time and expiration date
function getCurrentShowTimeSeconds() {
var curTime = new Date(a);var ret = endTime.getTime() - curTime.getTime();
ret = Math.round( ret/1000 )
return ret >= 0 ? ret : 0;
}
Copy the code
Draw a number dot
/ / change the value
let hours = parseInt( curShowTimeSeconds / 3600);
let minutes = parseInt( (curShowTimeSeconds - hours * 3600) /60 )
let seconds = curShowTimeSeconds % 60
Copy the code
Refresh to get the current dynamic time number
Thus the electronic clock was realized
Animation effect
Clock digital animation
The directory structure
Digin.js // A two-dimensional lattice that stores numbers
Countdown.js // Concrete logic
Index.html // The specific page
Timing rendering
Use setInterval() to render the animation
// countdown.js
window.onload = function(){
// Initialize the canvas
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
canvas.width = WINDOW_WIDTH;
canvas.height = WINDOW_HEIGHT;
curShowTimeSeconds = getCurrentShowTimeSeconds()
// Time render
setInterval(() = > {
render( context );
update() // Update the function
}, 50)}Copy the code
Update the clock
function update() {
// Next second clock
const nextShowTimeSeconds = getCurrentShowTimeSeconds()
let nextHours = parseInt( nextShowTimeSeconds / 3600);
let nextMinutes = parseInt( (nextShowTimeSeconds - nextHours * 3600) /60 )
let nextSeconds = nextShowTimeSeconds % 60
// The clock of the current second
let curHours = parseInt( curShowTimeSeconds / 3600);
let curMinutes = parseInt( (curShowTimeSeconds - curHours* 3600) /60 )
let curSeconds = curShowTimeSeconds % 60
// Update seconds
if(nextShowTimeSeconds ! = curShowTimeSeconds) { curShowTimeSeconds = nextShowTimeSeconds } }Copy the code
Update the canvas
function render( cxt ){
// Refresh the entire screen rectangle
cxt.clearRect(0.0, WINDOW_WIDTH, WINDOW_HEIGHT)
let hours = parseInt( curShowTimeSeconds / 3600);
let minutes = parseInt( (curShowTimeSeconds - hours * 3600) /60 )
let seconds = curShowTimeSeconds % 60
renderDigit( MARGIN_LEFT , MARGIN_TOP , parseInt(hours/10) , cxt )
renderDigit( MARGIN_LEFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(hours%10) , cxt )
renderDigit( MARGIN_LEFT + 30*(RADIUS + 1) , MARGIN_TOP , 10 , cxt )
renderDigit( MARGIN_LEFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(minutes/10) , cxt);
renderDigit( MARGIN_LEFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(minutes%10) , cxt);
renderDigit( MARGIN_LEFT + 69*(RADIUS+1) , MARGIN_TOP , 10 , cxt);
renderDigit( MARGIN_LEFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(seconds/10) , cxt);
renderDigit( MARGIN_LEFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(seconds%10) , cxt);
}
Copy the code
Small ball animation
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<canvas id="canvas" width="1024" height="768" style="border: 1px solid #aaa; display: block; margin: auto auto">
<! -- Compatible error reduction -->The current browser does not support Canvas. Please change your browser and try again</canvas>
<script>
// Initialize the ball
const ball = { x: 512.y: 100.r: 20.g: 2.vx: -4.vy: 0.color: '# 005588' }
window.onload = function() {
const canvas = document.getElementById('canvas')
// Draw context 2D drawing
const context = canvas.getContext('2d')
// Timer animation
setInterval(() = > {
/ / rendering
render(context)
/ / update
update()
}, 50)}/ / animation
function update() {
ball.x += ball.vx
ball.y += ball.vy
ball.vy += ball.g
// Hit the bottom
if (ball.y >= 768 - ball.r) {
ball.y = 768 - ball.r
ball.vy = -ball.vy*0.6 / / the friction}}function render(ctx) {
// Refresh the canvas
ctx.clearRect(0.0, ctx.canvas.width, ctx.canvas.height)
ctx.fillStyle = ball.color
ctx.beginPath()
ctx.arc(ball.x, ball.y, ball.r, 0.2*Math.PI)
ctx.closePath()
ctx.fill()
}
</script>
</body>
</html>
Copy the code
Clock ball animation
The directory structure
Digin.js // A two-dimensional lattice that stores numbers
Countdown.js // Concrete logic
Index.html // The specific page
Initialize data
/ / constant
const WINDOW_WIDTH = 1024;
const WINDOW_HEIGHT = 768;
const RADIUS = 8;
const MARGIN_TOP = 60;
const MARGIN_LEFT = 30;
const endTime = new Date(2021.3.7.0.0.0);
let curShowTimeSeconds = 0
// Store the ball
const balls = [];
// Change the color
const colors = ["#33B5E5"."#0099CC"."#AA66CC"."#9933CC"."#99CC00"."# 669900"."#FFBB33"."#FF8800"."#FF4444"."#CC0000"]
Copy the code
Update the ball
function update() {
// Next second clock
const nextShowTimeSeconds = getCurrentShowTimeSeconds()
let nextHours = parseInt(nextShowTimeSeconds / 3600);
let nextMinutes = parseInt((nextShowTimeSeconds - nextHours * 3600) / 60)
let nextSeconds = nextShowTimeSeconds % 60
// The clock of the current second
let curHours = parseInt(curShowTimeSeconds / 3600);
let curMinutes = parseInt((curShowTimeSeconds - curHours * 3600) / 60)
let curSeconds = curShowTimeSeconds % 60
// Update seconds
if(nextShowTimeSeconds ! = curShowTimeSeconds) {// Update all 6 numbers together
if (parseInt(curHours / 10) != parseInt(nextHours / 10)) {
// Add the ball
addBalls(MARGIN_LEFT + 0, MARGIN_TOP, parseInt(curHours / 10));
}
if (parseInt(curHours % 10) != parseInt(nextHours % 10)) {
addBalls(MARGIN_LEFT + 15 * (RADIUS + 1), MARGIN_TOP, parseInt(curHours / 10));
}
if (parseInt(curMinutes / 10) != parseInt(nextMinutes / 10)) {
addBalls(MARGIN_LEFT + 39 * (RADIUS + 1), MARGIN_TOP, parseInt(curMinutes / 10));
}
if (parseInt(curMinutes % 10) != parseInt(nextMinutes % 10)) {
addBalls(MARGIN_LEFT + 54 * (RADIUS + 1), MARGIN_TOP, parseInt(curMinutes % 10));
}
if (parseInt(curSeconds / 10) != parseInt(nextSeconds / 10)) {
addBalls(MARGIN_LEFT + 78 * (RADIUS + 1), MARGIN_TOP, parseInt(curSeconds / 10));
}
if (parseInt(curSeconds % 10) != parseInt(nextSeconds % 10)) {
addBalls(MARGIN_LEFT + 93 * (RADIUS + 1), MARGIN_TOP, parseInt(nextSeconds % 10));
}
curShowTimeSeconds = nextShowTimeSeconds;
}
/ / update the ball
updateBalls();
}
Copy the code
Add a small ball
// Add the ball
function addBalls(x, y, num) {
for (let i = 0; i < digit[num].length; i++)
for (let j = 0; j < digit[num][i].length; j++)
if (digit[num][i][j] == 1) {
const aBall = {
/ / the origin
x: x + j * 2 * (RADIUS + 1) + (RADIUS + 1),
y: y + i * 2 * (RADIUS + 1) + (RADIUS + 1),
// Animation random design
g: 1.5 + Math.random(),
vx: Math.pow(-1.Math.ceil(Math.random() * 1000)) * 4.vy: -5.color: colors[Math.floor(Math.random() * colors.length)]
}
balls.push(aBall)
}
}
Copy the code
Update ball movement
// Update the ball movement
function updateBalls() {
for (let i = 0; i < balls.length; i++) {
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
// Collision detection
if (balls[i].y >= WINDOW_HEIGHT - RADIUS) {
balls[i].y = WINDOW_HEIGHT - RADIUS;
balls[i].vy = -balls[i].vy * 0.75; }}}Copy the code
Draw the ball
// Draw each dot of the number
function render(cxt) {
// Refresh the entire screen rectangle
cxt.clearRect(0.0, WINDOW_WIDTH, WINDOW_HEIGHT)
let hours = parseInt(curShowTimeSeconds / 3600);
let minutes = parseInt((curShowTimeSeconds - hours * 3600) / 60)
let seconds = curShowTimeSeconds % 60
renderDigit(MARGIN_LEFT, MARGIN_TOP, parseInt(hours / 10), cxt)
renderDigit(MARGIN_LEFT + 15 * (RADIUS + 1), MARGIN_TOP, parseInt(hours % 10), cxt)
renderDigit(MARGIN_LEFT + 30 * (RADIUS + 1), MARGIN_TOP, 10, cxt)
renderDigit(MARGIN_LEFT + 39 * (RADIUS + 1), MARGIN_TOP, parseInt(minutes / 10), cxt);
renderDigit(MARGIN_LEFT + 54 * (RADIUS + 1), MARGIN_TOP, parseInt(minutes % 10), cxt);
renderDigit(MARGIN_LEFT + 69 * (RADIUS + 1), MARGIN_TOP, 10, cxt);
renderDigit(MARGIN_LEFT + 78 * (RADIUS + 1), MARGIN_TOP, parseInt(seconds / 10), cxt);
renderDigit(MARGIN_LEFT + 93 * (RADIUS + 1), MARGIN_TOP, parseInt(seconds % 10), cxt);
// Draw the ball
for (let i = 0; i < balls.length; i++) {
cxt.fillStyle = balls[i].color;
cxt.beginPath();
cxt.arc(balls[i].x, balls[i].y, RADIUS, 0.2 * Math.PI, true); cxt.closePath(); cxt.fill(); }}Copy the code
Optimize and extend the clock
Performance optimization
The directory structure
Digin.js // A two-dimensional lattice that stores numbers
Countdown.js // Concrete logic
Index.html // The specific page
implementation
Problem: The array of Balls keeps growing until it reaches a limit.
Fix: When the ball moves off the canvas, it should be deleted.
The ball array should only exist as the canvas appears with the ball (which will get slower and slower and card)
// Update the ball movement
function updateBalls() {
for (let i = 0; i < balls.length; i++) {
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
if (balls[i].y >= WINDOW_HEIGHT - RADIUS) {
balls[i].y = WINDOW_HEIGHT - RADIUS;
balls[i].vy = -balls[i].vy * 0.75; }}// Initialize the number to 0 => determine how many balls remain in the canvas
let cnt = 0
for( let i = 0 ; i < balls.length ; i ++ )
// Whether it is in the canvas
if( balls[i].x + RADIUS > 0 && balls[i].x -RADIUS < WINDOW_WIDTH )
// If yes, add the ball
balls[cnt++] = balls[i]
// Keep only the ball with the canvas
while( balls.length > cnt ){ balls.pop(); }}Copy the code
Screen adaptation
Let the initialized constant adapt to the current screen.
Prop up the width and height of the DOM element for fetching
<! DOCTYPEhtml>
<html style="height: 100%;">
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body style="height: 100%;">
<canvas id="canvas" style="height: 100%;">The current browser does not support Canvas. Please change your browser and try again</canvas>
<script src="digit.js"></script>
<script src="countdown.js"></script>
</body>
</html>
Copy the code
Dynamically define canvas initialization variables
// countdown.js
/ / constant
let WINDOW_WIDTH = 1024;
let WINDOW_HEIGHT = 768;
let RADIUS = 8;
let MARGIN_TOP = 60;
let MARGIN_LEFT = 30;
const endTime = new Date(2021.3.8.0.0.0);
let curShowTimeSeconds = 0
// Store the ball
const balls = [];
// Change the color
const colors = ["#33B5E5"."#0099CC"."#AA66CC"."#9933CC"."#99CC00"."# 669900"."#FFBB33"."#FF8800"."#FF4444"."#CC0000"]
window.onload = function () {
// Define constants based on the user screen
WINDOW_WIDTH = document.body.clientWidth;
WINDOW_HEIGHT = document.body.clientHeight;
MARGIN_LEFT = Math.round(WINDOW_WIDTH/10);
// Select * from renderDigit
RADIUS = Math.round(WINDOW_WIDTH * 4 / 5 / 108) -1
MARGIN_TOP = Math.round(WINDOW_HEIGHT / 5)
// Initialize the canvas
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
canvas.width = WINDOW_WIDTH;
canvas.height = WINDOW_HEIGHT;
curShowTimeSeconds = getCurrentShowTimeSeconds()
// Time render
setInterval(() = > {
render(context);
update() // Update the function
}, 50)}Copy the code
Reset time updated
Problem: If the defined endTime is less than 99 hours up to now => return 00:00:00
Solution: Dynamically obtain endTime
// Add one hour to the current time
let endTime = new Date()
endTime.setTime(endTime.getTime() + 3600 * 1000)
Copy the code
Gorgeous clock effect
Can do the effect of the current clock, not just the countdown
The focus is on getCurrentShowTimeSecond(), which returns how long the day has passed.
// Get the current time
function getCurrentShowTimeSeconds() {
let curTime = new Date(a);// Save is how long has passed today => clock
let ret = curTime.getHours() * 3600 + curTime.getMinutes() * 60 + curTime.getSeconds()
return ret
}
Copy the code
conclusion
Put on the canvas Api
The common methods and attributes used in this course are reviewed again.
Canvas
HTML
JavaScript
-
const canvas = document.getElementById('canvas') // Get the Canvas element const context = canvas.getContext('2d') // Get the context to draw Copy the code
-
Commonly used attributes
// The width and height of the current canvas
canvas.width
canvas.height
Copy the code
- Commonly used method
// Get the context of the current canvas
canvas.getContext('2d')
Copy the code
Context
- Commonly used attributes
/ / pen line width
context.lineWidth
// String color
context.strokeStyle
/ / fill color
context.fillStyle
// The canvas corresponding to the context
context.canvas
Copy the code
- Commonly used method
// Move the nib
context.moveTo(x, y)
Draw a line / /
context.lineTo(x, y)
/ / draw arc
context.arc(cx, cy, r, sAng, eAng, anticlock = false)
// Start painting
context.beginPath()
// Finish painting
context.closePath()
// Draw the pen line color
context.stroke()
// Fill the color
context.fill()
// Refresh the rectangle
context.clearRect(x, y, width, height)
Copy the code
Afterword.
Come on ~
Clean up your front-end architecture and find a good internship!