jotting
正是H5
的这么一项技术再加上adobe的svg
使得童年的flash逐渐退出了历史的舞台,就像我们不能一直玩洛克王国,玩4399的各种小游戏一样,我们也不可能一直使用旧的技术,web前端再以一种很快的速度更新迭代,技术一直在发展,日新月异。从vue2
到vue3
,从react
的类式组件
到函数式组件
,从初识css in js
的激动不已到css in js
的emotion
库的主要贡献者提出因为性能的缺陷弃用css in js
而采用Sass Modules
等等等 ,我初识前端就感受到了它的发展之快,不断的迭代。
从21年初次学习使用canvas
到现在也过去了一年多的时间了,我很喜欢canvas
但是我在实际的各个项目中使用的少之又少,在写数据可视化相关的项目时,我也没有去自己使用canvas
去写各种效果,因为会占用很多时间,并没有大把的数据可视化的库来的方便,导致很多canvas
的特性也早就忘的差不多了,webgl
我很感兴趣,three.js
我认为拿这些3D
的东西写出的页面很炫酷,需要很牢靠的数学支撑,我也在各种的说国内webgl
岗位并不多、少等等等中,并未深入学习。这是一篇我复习canvas的一些特性的简单文章。
21年使用canvas
画的国旗
go over canvas
canvas
标签创建了一个固定大小的画布,公开了一个或多个渲染的上下文,我们想要绘制就要先找到上下文
canvas
提供了一个方法—getContext()
通过此方法我们就可以获取渲染上下文和绘画功能
上下文类型(contextType)
是一个指示使用何种上下文的 DOMString
。可能的值是:
"2d
", 建立一个CanvasRenderingContext2D
二维渲染上下文。"webgl"
(或"experimental-webgl"
) 这将创建一个WebGLRenderingContext
三维渲染上下文对象。只在实现WebGL 版本 1(OpenGL ES 2.0) 的浏览器上可用。- "
webgl2
" (或 "experimental-webgl2
") 这将创建一个WebGL2RenderingContext
三维渲染上下文对象。只在实现 WebGL 版本 2 (OpenGL ES 3.0) 的浏览器上可用。实验性 "bitmaprenderer"
这将创建一个只提供将 canvas 内容替换为指定ImageBitmap
功能的ImageBitmapRenderingContext
。
线
moveTo(x, y)
设置初始位置,参数为初始位置x和y的坐标点
lineTo(x, y)
绘制一条从初始位置到指定位置的直线,参数为指定位置x和y的坐标点
stroke()
通过线条来绘制图形轮廓
//简单画三角形
<style>
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas')
if(canvas.getContext) {
var ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(50,50)
ctx.lineTo(200,200)
ctx.lineTo(200,50)
ctx.lineTo(50,50)
ctx.fill()
ctx.stroke()
}
</script>
//简单画三角形
<style>
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas')
if(canvas.getContext) {
var ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.moveTo(50,50)
ctx.lineTo(200,200)
ctx.lineTo(200,50)
ctx.lineTo(50,50)
ctx.fill()
ctx.stroke()
}
</script>
矩形
x和y 是矩形的起点坐标,width和height 是矩形的宽高。
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
圆和圆弧
绘制圆弧或者圆,我们使用arc()
方法。当然可以使用arcTo()
,不过这个的实现并不是那么的可靠,所以我们这里不作介绍。
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以 radius 为半径的圆弧(圆),从 startAngle 开始到 endAngle 结束,按照 anticlockwise 给定的方向(默认为顺时针)来生成。
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
这里详细介绍一下 arc 方法,该方法有六个参数:x,y
为绘制圆弧所在圆上的圆心坐标。radius
为半径。startAngle
以及endAngle
参数用弧度定义了开始以及结束的弧度。这些都是以 x 轴为基准。参数anticlockwise
为一个布尔值。为 true 时,是逆时针方向,否则顺时针方向。
👻备注: arc()
函数中表示角的单位是弧度,不是角度。角度与弧度的 js 表达式:
弧度=(Math.PI/180)*角度。
二次贝塞尔曲线及三次贝塞尔曲线
二次及三次贝塞尔曲线都十分有用,一般用来绘制复杂有规律的图形(贝塞尔曲线)。
quadraticCurveTo(cp1x, cp1y, x, y)
quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y
为一个控制点,x,y
为结束点。
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y
为控制点一,cp2x,cp2y
为控制点二,x,y
为结束点。
右边的图能够很好的描述两者的关系,二次贝塞尔曲线有一个开始点(蓝色)、一个结束点(蓝色)以及一个控制点(红色),而三次贝塞尔曲线有两个控制点。
参数 x、y 在这两个方法中都是结束点坐标。cp1x,cp1y
为坐标中的第一个控制点,cp2x,cp2y
为坐标中的第二个控制点。
使用二次以及三次贝塞尔曲线是有一定的难度的,因为不同于像 Adobe Illustrators 这样的矢量软件,我们所绘制的曲线没有给我们提供直接的视觉反馈。这让绘制复杂的图形变得十分困难。在下面的例子中,我们会绘制一些简单有规律的图形,如果你有时间以及更多的耐心,很多复杂的图形你也可以绘制出来。
这里也可以借助一个网页版的三次贝塞尔曲线调试工具来看效果
椭圆
添加椭圆路径。
语法:ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
- x、y:椭圆的圆心位置
- radiusX、radiusY:x轴和y轴的半径
- rotation:椭圆的旋转角度,以弧度表示
- startAngle:开始绘制点
- endAngle:结束绘制点
- anticlockwise:绘制的方向(默认顺时针),可选参数。
矩形
直接在画布上绘制矩形的三个额外方法,正如我们开始所见的-绘制矩形,同样,也有 rect() 方法,将一个矩形路径增加到当前路径上。
rect(x, y, width, height)
绘制一个左上角坐标为(x,y),宽高为 width 以及 height 的矩形。
当该方法执行的时候,moveTo() 方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置回默认坐标。
绘制样式
线条的样式
线条的样式可以通过下面一系列属性来设置。
lineWidth
lineWidth 设置当前绘线的粗细。属性值必须为正数。默认值是 1.0。
lineCap
lineCap 设置线段端点显示的样子。可选值为:butt,round 和 square。默认是 butt。
lineJoin
lineJoin 该属性可以设置两线段连接处所显示的样子。可选值为:round, bevel 和 miter。默认是 miter。
miterLimit
miterLimit 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
线段之间夹角比较大时,交点不会太远,但随着夹角变小,交点距离会呈指数级增大。
如果交点距离大于miterLimit值,连接效果会变成了 lineJoin = bevel 的效果。
setLineDash/getLineDash
setLineDash 可以设置当前虚线样式。
getLineDash 则是返回当前虚线设置的样式,长度为非负偶数的数组。
lineDashOffset
lineDashOffset 设置虚线样式的起始偏移量。
透明度
除了绘制实色的图形,还可以绘制有透明度的图形。通过设置 globalAlpha 属性或者使用有透明度的样式作为轮廓或填充都可以实现
等等各种样式[可见MDN文档](使用样式和颜色 - Web API 接口参考 | MDN (mozilla.org))
绘制文本
canvas 提供了两种方法来渲染文本:
fillText(text, x, y [, maxWidth\])
在指定的 (x,y) 位置填充指定的文本,绘制的最大宽度是可选的。
strokeText(text, x, y [, maxWidth\])
在指定的 (x,y) 位置绘制文本边框,绘制的最大宽度是可选的。
同样文本的样式也可以改变
动画
绘制小球
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 动画</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
ball.draw();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 动画</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
ball.draw();
}
</script>
</body>
</html>
速率
我们通过给小球添加速率矢量进行移动。这个依旧用requestAnimationFrame() 方法来实现,在每一帧里面,依旧用clear 清理掉之前帧里旧的圆形。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ball.draw();
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
边界
想让小球反弹那么我们就需要添加边界
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ball.draw();
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ball.draw();
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
加速度
为了让动作更真实,我们还需要加入加速度的处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ball.draw();
// 添加加速度
ball.vy *= .99;
ball.vy += .25;
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height);
ball.draw();
// 添加加速度
ball.vy *= .99;
ball.vy += .25;
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
拖尾效果
加一个拖尾效果:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// 用带透明度的矩形代替清空
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ball.draw();
// 添加加速度
ball.vy *= .995;
ball.vy += .15;
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas - 裁剪</title>
<style>
/* 给画布增加一个阴影和圆角的样式 */
canvas {
box-shadow: 0px 0px 5px #ccc;
border-radius: 8px;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500">
当前浏览器不支持canvas元素,请升级或更换浏览器!
</canvas>
<script>
// 获取 canvas 元素
var canvas = document.getElementById('canvas');
// 通过判断getContext方法是否存在来判断浏览器的支持性
if(canvas.getContext) {
// 获取绘图上下文
var ctx = canvas.getContext('2d');
var ball = {
x: 100,
y: 100,
vx: 1,
vy: 3,
radius: 25,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// 用带透明度的矩形代替清空
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ball.draw();
// 添加加速度
ball.vy *= .995;
ball.vy += .15;
// 添加速率
ball.x += ball.vx;
ball.y += ball.vy;
// 添加边界
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
ball.draw();
}
</script>
</body>
</html>
在taro中使用canvas
最近在写taro的项目时用到了canvas在其中画一个添加的样式,在taro中使用总体上与微信小程序一致。很简单的画了两条线。
import { View, Canvas } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { useEffect, useState } from "react";
import styles from "./index.module.css";
const HFloatingButton = () => {
const [outStartCoordinate, setOutStartCoordinate] = useState([0, 0]); // 移动前的位置
const [outMoveCoordinate, setOutMoveCoordinate] = useState([330, 570]); // 移动后的位置
const [constraintSize, setConstraintSize] = useState<Array<number>>([]); // 可视区的范围
// 获取可视区的范围
useEffect(() => {
const res = Taro.getSystemInfoSync();
setConstraintSize([res.windowWidth, res.windowHeight]);
const ctx = Taro.createCanvasContext("myCanvas"); //此处开始绘画
ctx.moveTo(7, 22.5);
ctx.lineTo(37, 22.5);
ctx.setLineWidth(2.5);
ctx.moveTo(22.5, 7);
ctx.lineTo(22.5, 37);
ctx.setStrokeStyle("white");
ctx.stroke();
ctx.draw();
}, []);
// 判断是否超出边界
const compareIsBeyond = (x: number, y: number) => {
if (x >= constraintSize[0] - 45) {
x = constraintSize[0] - 45;
} else if (x < 45) {
x = 0;
} else {
x -= 22.5;
}
if (y >= constraintSize[1] - 45) {
y = constraintSize[0] - 45;
} else if (y < 45) {
y = 0;
} else {
y -= 22.5;
}
return [x, y];
};
return (
<View
className={styles["out-circle"]}
style={{
width: "45px",
height: "45px",
left: `${outMoveCoordinate[0]}px`,
top: `${outMoveCoordinate[1]}px`
}}
onTouchStart={e => {
const { clientX, clientY } = e.changedTouches[0];
setOutStartCoordinate([clientX, clientY]);
}}
onTouchMove={e => {
e.stopPropagation();
let { clientX, clientY } = e.changedTouches[0];
let res = compareIsBeyond(clientX, clientY);
setOutMoveCoordinate(res);
}}
>
<>
{" "}
<Canvas
canvasId="myCanvas"
id="myCanvas"
style={{ width: "45px", height: "45px" }}
></Canvas>
</>
</View>
);
};
import { View, Canvas } from "@tarojs/components";
import Taro from "@tarojs/taro";
import { useEffect, useState } from "react";
import styles from "./index.module.css";
const HFloatingButton = () => {
const [outStartCoordinate, setOutStartCoordinate] = useState([0, 0]); // 移动前的位置
const [outMoveCoordinate, setOutMoveCoordinate] = useState([330, 570]); // 移动后的位置
const [constraintSize, setConstraintSize] = useState<Array<number>>([]); // 可视区的范围
// 获取可视区的范围
useEffect(() => {
const res = Taro.getSystemInfoSync();
setConstraintSize([res.windowWidth, res.windowHeight]);
const ctx = Taro.createCanvasContext("myCanvas"); //此处开始绘画
ctx.moveTo(7, 22.5);
ctx.lineTo(37, 22.5);
ctx.setLineWidth(2.5);
ctx.moveTo(22.5, 7);
ctx.lineTo(22.5, 37);
ctx.setStrokeStyle("white");
ctx.stroke();
ctx.draw();
}, []);
// 判断是否超出边界
const compareIsBeyond = (x: number, y: number) => {
if (x >= constraintSize[0] - 45) {
x = constraintSize[0] - 45;
} else if (x < 45) {
x = 0;
} else {
x -= 22.5;
}
if (y >= constraintSize[1] - 45) {
y = constraintSize[0] - 45;
} else if (y < 45) {
y = 0;
} else {
y -= 22.5;
}
return [x, y];
};
return (
<View
className={styles["out-circle"]}
style={{
width: "45px",
height: "45px",
left: `${outMoveCoordinate[0]}px`,
top: `${outMoveCoordinate[1]}px`
}}
onTouchStart={e => {
const { clientX, clientY } = e.changedTouches[0];
setOutStartCoordinate([clientX, clientY]);
}}
onTouchMove={e => {
e.stopPropagation();
let { clientX, clientY } = e.changedTouches[0];
let res = compareIsBeyond(clientX, clientY);
setOutMoveCoordinate(res);
}}
>
<>
{" "}
<Canvas
canvasId="myCanvas"
id="myCanvas"
style={{ width: "45px", height: "45px" }}
></Canvas>
</>
</View>
);
};
.out-circle {
border-radius: 50%;
background-color: #5956E9;
position: fixed;
}
.out-circle {
border-radius: 50%;
background-color: #5956E9;
position: fixed;
}