依次解除注释看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas practice</title>
</head>
<style>
canvas {
border: 1px solid black;
}
</style>
<body>
<canvas id="canvas" width="300" height="300">
您的浏览器太老了,不支持canvas,请升级您的浏览器!
</canvas>
<p>
1、lineTo、arc、arcTo、bezierCurveTo、quadraticCurveTo等方法是绘制路径(此时还不可见),stroke方法是将路径画出来(应用了样式,此时可见了)
</p>
<p>
2、stroke方法用来描边、fill方法用来填充
</p>
<p>
3、贝塞尔曲线关键点:两个点连线上的点匀速运动;以相同的时间从起点到终点
</p>
</body>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script>
// get canvas dom object
let canvas = $('#canvas')[0];
// get canvas 2D context
let ctx = canvas.getContext('2d');
// check if browser support canvas
if (ctx) {
console.info('support');
/*ctx.fillStyle = 'rgb(200,0,0)';
ctx.fillRect(10,10,55,50);
ctx.fillStyle = 'rgba(0,0,200,0.5)';
ctx.fillRect(30,30,55,50);*/
/*ctx.fillRect(10,10,100,50);
ctx.strokeRect(10,70,100,50);
ctx.clearRect(15,15,50,25);*/
/*ctx.beginPath();//使用路径指令
ctx.moveTo(0,50);//设置起点
ctx.lineTo(300,50);//绘制路径,使用直线绘制
ctx.closePath();//闭合路径
ctx.stroke();//使用样式将路径画出来,这里因为没有指定,使用默认样式*/
/*ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(200,50);
ctx.lineTo(200,200);
//ctx.closePath();
ctx.stroke();
ctx.fillStyle = 'yellow';
ctx.fill();//fill具有自动闭合的功能,但不能应用描边的样式*/
/*ctx.beginPath();
ctx.arc(50,50,40,0, Math.PI/2,true);
ctx.closePath();
ctx.stroke();
ctx.fillStyle = 'yellow';
ctx.fill();*/
/*ctx.beginPath();
ctx.moveTo(50,50);
ctx.arcTo(200,50,200,200,100);
ctx.stroke();*/
/*ctx.beginPath();
ctx.moveTo(10,200);
let cp1x = 40, cp1y = 100;
let x = 200, y = 200;
ctx.quadraticCurveTo(cp1x,cp1y,x,y);
ctx.stroke();*/
/*ctx.beginPath();
ctx.moveTo(40, 200);
let cp1x = 20, cp1y = 100;
let cp2x = 100, cp2y = 120;
let x = 200, y = 200;
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
ctx.stroke();*/
/*for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)},${Math.floor(255 - 42.5 * j)},0`;
ctx.fillRect(j * 50, i * 50, 50, 50);
}
}*/
/*function randomInt(from, to) {
return parseInt(Math.random() * (to - from + 1) + from);
}
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
ctx.strokeRect(j * 50, i * 50, 40, 40);
}
}*/
/*ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(100,10);
ctx.lineWidth = 10;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(110,10);
ctx.lineTo(160,10);
ctx.lineWidth = 20;
ctx.stroke();*/
/*let lineCaps = ['button', 'round', 'square'];
for (let i = 0; i < 3; i++) {
ctx.beginPath();
ctx.moveTo(20 + 30 * i, 30);
ctx.lineTo(20 + 30 * i, 100);
ctx.lineWidth = 20;
ctx.lineCap = lineCaps[i];
ctx.stroke();
}
ctx.beginPath();
ctx.moveTo(0, 30);
ctx.lineTo(300, 30);
ctx.moveTo(0, 100);
ctx.lineTo(300, 100);
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.stroke();*/
/*let lineJoin = ['round', 'bevel', 'miter'];
ctx.lineWidth = 20;
for (let i = 0; i < 3; i++) {
ctx.lineJoin = lineJoin[i];
ctx.beginPath();//试一下,如果将这行代码放在for循环之前,会发生什么事情
ctx.moveTo(50, 50 + i * 50);
ctx.lineTo(100, 100 + i * 50);
ctx.lineTo(150, 50 + i * 50);
ctx.lineTo(200, 100 + i * 50);
ctx.lineTo(250, 50 + i * 50);
ctx.stroke();
}*/
/*ctx.setLineDash([20, 5]);
ctx.lineDashOffset = 0;
ctx.strokeRect(50, 50, 210, 210);
console.log(ctx.getLineDash());*/
/*ctx.font = '30px sans-serif';
ctx.direction = 'ltr';//need to enable chrome feature
ctx.strokeStyle = 'rgba(188,165,34,0.5)';
ctx.fillText('何事秋风悲画扇',10,100);
ctx.strokeText('那人却在灯火阑珊处',10,200);*/
/*let img = new Image();
img.src = 'https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2398393444,3602364069&fm=173&app=25&f=JPEG?w=640&h=390&s=2CC46B840A73649A8A819118030080D0';
img.onload = function () {
const naturalWidth = img.naturalWidth;
const naturalHeight = img.naturalHeight;//modern browser
console.log(img.height);//old browser
if (naturalWidth > naturalHeight) {
ctx.drawImage(img, 0, 0, 300, naturalHeight * 300 / naturalWidth);
} else {
ctx.drawImage(img, 0, 0, 300 * naturalWidth / naturalHeight, 300);
}
//drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
ctx.drawImage(img, 260, 70, 100, 100, 10, 200, 100, 100);//sx, sy指的是以图片原始大小为基础进行的定位
};*/
/*ctx.fillRect(0,0,150,150);
ctx.save();
ctx.fillStyle = 'red';
ctx.fillRect(15,15,120,120);
ctx.save();
ctx.fillStyle = '#fff';
ctx.fillRect(30, 30, 90, 90);
ctx.restore();
ctx.fillRect(45, 45, 60, 60);//should be red
ctx.restore();
ctx.fillRect(60, 60, 30, 30);//should be black(default)*/
/*ctx.save();//就像push方法,将当前状态压入栈中
ctx.translate(100, 100);
ctx.strokeRect(0, 0, 100, 100);
ctx.restore();//就像pop方法,将栈顶状态弹出来
ctx.translate(220, 220);//想想如果不执行restore方法,执行完这行代码后会发生什么情况
ctx.fillRect(0, 0, 50, 50);*/
/*ctx.fillStyle = "red";
ctx.save();
ctx.translate(100, 100);
ctx.rotate(Math.PI / 180 * 45);
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 100, 100);
ctx.restore();
ctx.fillRect(0, 0, 50, 50);*/
/*ctx.fillRect(0, 0, 100, 100);
ctx.scale(0.5,0.5);
ctx.fillStyle = 'gray';
ctx.fillRect(200, 200, 100, 100);//注意x、y点应该是200,实际的定位点经过缩小到0.5倍后,就是看到的(100,100)的位置
ctx.restore();*/
/*//随机展示
let globalCompositeOperation = ['source-over', 'source-in', 'source-out',
'source-atop', 'destination-over', 'destination-in',
'destination-out', 'destination-atop', 'lighter',
'darken', 'lighten', 'xor', 'copy'];
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 200, 200);
let i = Math.floor(Math.random() * 13);//向下取整
let selected = globalCompositeOperation[i];
console.log('random globalCompositeOperation is:', selected);
ctx.globalCompositeOperation = selected; //全局合成操作
ctx.fillStyle = "red";
ctx.fillRect(100, 100, 200, 200);
ctx.beginPath();
ctx.arc(20,20, 100, 0, Math.PI * 2);
ctx.clip();//试着注释掉这行代码看看效果
ctx.fillStyle = "pink";
ctx.fillRect(20, 20, 100,100);*/
} else {
console.error('sorry');
}
</script>
</html>
转载simulation clock实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>simulation clock</title>
<style>
body {
padding: 0;
margin: 0;
background-color: rgba(0, 0, 0, 0.1)
}
canvas {
display: block;
margin: 200px auto;
background: black;
}
</style>
</head>
<body>
<canvas id="simulation-clock" width="300" height="300"></canvas>
<script>
init();
function init() {
let canvas = document.querySelector("#simulation-clock");
let ctx = canvas.getContext("2d");
draw(ctx);
}
function draw(ctx) {
requestAnimationFrame(function step() {
drawDial(ctx); //绘制表盘
drawAllHands(ctx); //绘制时分秒针
requestAnimationFrame(step);
});
}
/*绘制时分秒针*/
function drawAllHands(ctx) {
let time = new Date();
let s = time.getSeconds();
let m = time.getMinutes();
let h = time.getHours();
let pi = Math.PI;
let secondAngle = pi / 180 * 6 * s; //计算出来s针的弧度
let minuteAngle = pi / 180 * 6 * m + secondAngle / 60; //计算出来分针的弧度
let hourAngle = pi / 180 * 30 * h + minuteAngle / 12; //计算出来时针的弧度
drawHand(hourAngle, 60, 6, "red", ctx); //绘制时针
drawHand(minuteAngle, 106, 4, "green", ctx); //绘制分针
drawHand(secondAngle, 129, 2, "blue", ctx); //绘制秒针
}
/*绘制时针、或分针、或秒针
* 参数1:要绘制的针的角度
* 参数2:要绘制的针的长度
* 参数3:要绘制的针的宽度
* 参数4:要绘制的针的颜色
* 参数4:ctx
* */
function drawHand(angle, len, width, color, ctx) {
ctx.save();
ctx.translate(150, 150); //把坐标轴的远点平移到原来的中心
ctx.rotate(-Math.PI / 2 + angle); //旋转坐标轴。 x轴就是针的角度
ctx.beginPath();
ctx.moveTo(-4, 0);
ctx.lineTo(len, 0); // 沿着x轴绘制针
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.lineCap = "round";
ctx.stroke();
ctx.closePath();
ctx.restore();
}
/*绘制表盘*/
function drawDial(ctx) {
let pi = Math.PI;
ctx.clearRect(0, 0, 300, 300); //清除所有内容
ctx.save();
ctx.translate(150, 150); //一定坐标原点到原来的中心
ctx.beginPath();
ctx.arc(0, 0, 148, 0, 2 * pi); //绘制圆周
ctx.stroke();
ctx.closePath();
for (let i = 0; i < 60; i++) {//绘制刻度。
ctx.save();
ctx.rotate(-pi / 2 + i * pi / 30); //旋转坐标轴。坐标轴x的正方形从 向上开始算起
ctx.beginPath();
ctx.moveTo(110, 0);
ctx.lineTo(140, 0);
ctx.lineWidth = i % 5 ? 2 : 4;
ctx.strokeStyle = i % 5 ? "blue" : "red";
ctx.stroke();
ctx.closePath();
ctx.restore();
}
ctx.restore();
}
</script>
</body>
</html>
网友评论