Canvas之绘制图形后续

Canvas之绘制图形后续

Canvas 提供了一些线条 API ,它可以设置 ctx.lineCap 线条的端点,ctx.lineJoin 线条的折线连接处,ctx.miterLimit 控制线条折线的尖角长短。

js 复制代码
ctx.beginPath();
ctx.lineWidth = 10;
ctx.strokeStyle = 'red';
ctx.lineCap ="butt"; //平的
ctx.moveTo(50, 50)
ctx.lineTo(300, 50);
ctx.stroke();

ctx.beginPath();
ctx.lineCap="round" //突出圆
ctx.moveTo(50, 100)
ctx.lineTo(300, 100);
ctx.stroke();

ctx.beginPath();
ctx.lineCap="square" //突出平
ctx.moveTo(50, 150)
ctx.lineTo(300, 150);
ctx.stroke();
js 复制代码
ctx.beginPath();
ctx.lineWidth = 10;
ctx.strokeStyle = 'red';
ctx.lineJoin = "miter";//尖的
ctx.moveTo(50, 50);
ctx.lineTo(150, 150);
ctx.lineTo(250, 50);
ctx.stroke();

ctx.beginPath();
ctx.lineJoin = "round";//圆的
ctx.moveTo(50, 100);
ctx.lineTo(150, 200);
ctx.lineTo(250, 100);
ctx.stroke();

ctx.beginPath();
ctx.lineJoin = "bevel";//平的
ctx.moveTo(50, 150);
ctx.lineTo(150, 250);
ctx.lineTo(250, 150);
ctx.stroke();
js 复制代码
ctx.beginPath();
ctx.lineWidth = 20;
ctx.strokeStyle = 'red';
ctx.lineJoin = "miter";
ctx.miterLimit = 2;
ctx.moveTo(50, 50);
ctx.lineTo(70, 100);
ctx.lineTo(100, 50);
ctx.stroke();

ctx.beginPath();
ctx.lineWidth = 40;
ctx.miterLimit = 2;
ctx.moveTo(150, 50);
ctx.lineTo(170, 100);
ctx.lineTo(200, 50);
ctx.stroke();

ctx.miterLimit 会根据 ctx.lineWidth 来设置相应的比例进行长短变化。不同宽度设置同一个 ctx.miterLimit 长短不一致。

js 复制代码
ctx.beginPath();
ctx.moveTo(50, 100);
ctx.lineTo(200, 100);
ctx.setLineDash([200])
ctx.lineDashOffset = 200;
// ctx.lineDashOffset = -50;
ctx.lineWidth = 10;
ctx.strokeStyle = 'blue';
ctx.stroke();

function move() {
    ctx.lineDashOffset -= 1;
    console.log(ctx.lineDashOffset);
    ctx.stroke();
    if (ctx.lineDashOffset > -200) {
        requestAnimationFrame(move);
    }
}
requestAnimationFrame(move);

同样可以设置虚线,由于需要知道虚线实线长和空白长,需要一个数组,前面表示实线长,后面表示空白长。如果只设置一个数据,表示实线和空白长度相同。如果设置更多数据,表示重复循环设置。最好设置成偶数个数,这样就是一组。

同时,也可以设置偏移量。负数向右,正数向左偏移。

js 复制代码
ctx.beginPath();
ctx.lineWidth=10;
ctx.moveTo(0, 50);
ctx.lineTo(400, 50);
ctx.stroke();

ctx.clearRect(0, 0, canvas.width, canvas.height);

// ctx.beginPath();
ctx.lineWidth=10;
ctx.moveTo(50, 0);
ctx.lineTo(50, 400);
ctx.stroke();

在之前的虚线移动动画中,并不是真的移动,而是我们在不断进行重新描边,所以之前的线条依然被保留。只是因为线条在不断加长,所以没有看到问题。当让线条继续向右移动时,本该出现的空白就会被原来的线条挡住。

可以通过设置清除画布的区域来进行处理。如果设置的区域是整个画布,那么整个画布会被清除。注意,要使用 ctx.beginPath() ,如果不使用,清除画布只是设置了透明度,会保留原来的路径,在绘制时会全部画出。

js 复制代码
ctx.setLineDash([200])
ctx.lineDashOffset = 200;
ctx.lineWidth = 10;
ctx.strokeStyle = 'blue';

function move() {
    ctx.clearRect(50, 95, 200, 10);
    ctx.beginPath();
    ctx.moveTo(50, 100);
    ctx.lineTo(200, 100);
    ctx.lineDashOffset -= 1;
    ctx.stroke();
    if (ctx.lineDashOffset === -200) {
        ctx.lineDashOffset = 200;
    }
    requestAnimationFrame(move);
}
requestAnimationFrame(move);

我们可以实现简单的动画。在每一次动画前清除动画,设置 ctx.beginPath() ,然后不断递归,每次使得偏移量减一。当偏移量达到最低时,重新设置偏移量。

js 复制代码
ctx.beginPath();
ctx.lineWidth = 10;
ctx.moveTo(50, 50);
ctx.lineTo(50, 200);
ctx.lineTo(200, 200)
// ctx.lineTo(50, 50)
ctx.closePath();
ctx.stroke(); 
ctx.fill()

线条形成区域设置填充效果会将相关区域填充。但这时会出现最后端点闭合的样式问题,因为最后的端点并没有相连。所以想要实现自动闭合 ctx.closePath() 会解决这个问题。

而且不管是一条线段还是已经闭合的区域,自动闭合都会有效果,只是效果不太明显。

js 复制代码
ctx.beginPath();
ctx.arc(100,100,50,0,Math.PI * 2) ;
ctx.stroke();

ctx.beginPath();
ctx.arc(300,100,50,0,Math.PI,true);
ctx.stroke();

ctx.beginPath();
ctx.arc(100,300,50,Math.PI/2,Math.PI,true);
ctx.stroke();
js 复制代码
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(100,300);
ctx.lineTo(300,300);
ctx.stroke();

ctx.beginPath();
ctx.arc(200,200,100,0,Math.PI * 2);
ctx.stroke();

ctx.beginPath();
ctx.lineWidth = 4 ;
ctx.strokeStyle = '#00f';
ctx.moveTo(100,200);
ctx.arcTo(100,300,200,300,100);
ctx.stroke();

可以使用 ctx.arc( x , y , r , startAngle , endAngle ,[ dir ]),需要知道圆点,半径,起始点,结束点,绘制方向可选。起始点都是顺时针方向的,从x轴右侧作为起始点。false 默认为顺时针,true 为逆时针。

还可以使用 ctx.arcTo( x1 , y1 , x2 , y2 , r )实际由三个点相切,第一个点为 moveTo 的点或者是上一次绘制的结果,剩下的点为自己设置。会形成一个有夹角的线条,保证一段和线条相切的圆弧。

js 复制代码
ctx.beginPath();
ctx.ellipse(100, 100, 100, 50, 0, 0, Math.PI * 2);
ctx.stroke();

ctx.beginPath();
ctx.ellipse(300, 100, 100, 50, 0, 0, Math.PI / 2);
ctx.stroke();

ctx.beginPath();
ctx.ellipse(100, 300, 100, 50, Math.PI / 4, 0, Math.PI * 2);
ctx.stroke();

除了可以设置圆弧,还可以设置椭圆。ctx.ellipse( x , y , rx , ry , rotate , startAngle , endAngle , dir ) 需要增加 x 轴,y 轴,x 轴旋转角度,旋转角度默认为顺时针。其他和之前设置圆弧的方式相同。

js 复制代码
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.arc(100, 300, 5, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(200, 100, 5, 0, Math.PI * 2)
ctx.fill();
ctx.beginPath()
ctx.arc(300, 300, 5, 0, Math.PI * 2)
ctx.fill();

ctx.beginPath();
ctx.moveTo(100, 300);
ctx.quadraticCurveTo(200, 100, 300, 300)
ctx.stroke();
js 复制代码
ctx.beginPath();
ctx.moveTo(100, 300);
ctx.bezierCurveTo(200, 100, 250, 350, 300, 300)
ctx.stroke();

为了更好地设置曲线,可以采用贝塞尔曲线来进行绘制。除了起始点和结束点,还需要设置一些控制点。一个控制点叫做二次贝塞尔曲线,两个控制点叫做三次贝塞尔曲线。

设置一个参数 t ,数值为从0到1,不断找符合参数比例的点连线,直到找到最后一个点,然后这个点就是曲线的切点,这个点所在的直线叫做切线。这样随着参数 t 不断变化,就会得到一条最终的曲线。

前面是二次贝塞尔曲线,ctx.quadraticCurveTo( cx1 , cy1 , ex , ey),参数为控制点和结束点坐标,起始点坐标为前面给出的坐标。后面是三次贝塞尔曲线,bezierCurveTo(cx1,cy1 , cx2 , cy2 , ex , ey) 多了一个控制点坐标。

可以看到,贝塞尔曲线最多只能达到中间的位置,不会离控制点太过靠近。

js 复制代码
ctx.beginPath();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = 'bold italic 50px sans-serif'
ctx.fillText('你好', 100, 100)

ctx.beginPath();
ctx.font = 'bold italic 50px sans-serif'
ctx.strokeText('你好', 100, 200)

ctx.beginPath();
ctx.fillStyle = '#f00'
ctx.arc(100, 100, 5, 0, Math.PI * 2)
ctx.fill();
ctx.beginPath();
ctx.fillStyle = '#f00'
ctx.arc(100, 200, 5, 0, Math.PI * 2)
ctx.fill();

同样字体也可以被绘制出来,使用填充或者描边的形式绘制。ctx.fillText(textStr , x , y [, maxWidth])分别是绘制的文本,坐标和最大的宽度。如果超过了最大宽度,就会整体压缩到最大宽度。

还需要在绘制之前设置字体样式,记住一定要在最后设置字体,否则样式无法显示。

使用 ctx.textAlign 和 ctx.textBaseline 分别设置水平位置和垂直位置。center 表示水平居中,middle 表示垂直居中。

相关推荐
摇滚侠24 分钟前
JavaScript 浮点数计算精度错误示例
开发语言·javascript·ecmascript
xw542 分钟前
Trae安装指定版本的插件
前端·trae
天蓝色的鱼鱼1 小时前
JavaScript垃圾回收:你不知道的内存管理秘密
javascript·面试
默默地离开1 小时前
前端开发中的 Mock 实践与接口联调技巧
前端·后端·设计模式
南岸月明1 小时前
做副业,稳住心态,不靠鸡汤!我的实操经验之路
前端
嘗_1 小时前
暑期前端训练day7——有关vue-diff算法的思考
前端·vue.js·算法
MediaTea1 小时前
Python 库手册:html.parser HTML 解析模块
开发语言·前端·python·html
杨荧1 小时前
基于爬虫技术的电影数据可视化系统 Python+Django+Vue.js
开发语言·前端·vue.js·后端·爬虫·python·信息可视化
BD_Marathon2 小时前
IDEA中创建Maven Web项目
前端·maven·intellij-idea
waillyer2 小时前
taro跳转路由取值
前端·javascript·taro