我就不信,你不知道这些 Canvas 线条属性

线条样式

前言

"唰","唰","唰",还记得学习素描的时候,我们会用不同的笔来绘制各种各样的线条,有粗有细,有虚有实,有深有浅,有平行有相交。这一节我们将拿起画笔,就单纯的画画线,打打底子。那么在 Canvas 中,是通过什么属性或者方法来定义线条的样式呢?

为了本文讲解,本文中所有的 Canvas 上下文用 ctx 对象来表示

lineWidth 属性

js 复制代码
ctx.lineWidth = 整数;

Linewidth 属性取值为整数,默认为1,单位 px。

这个属性前面的文章也用过,没有做任何的讲解,但是我想大家应该看了就知道这就是线宽的设置,通过文本意义应该一目了然。

js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 10;
  ctx.strokeStyle = "hotpink";
  ctx.moveTo(20, 30);
  ctx.lineTo(180, 30);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = 5;
  ctx.moveTo(20, 70);
  ctx.lineTo(180, 70);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(20, 120);
  ctx.lineTo(180, 120);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>

我们结合图和代码来看一下,第二条线和第三条线为啥线宽是一样的 5px 呢?那是因为在每一次绘制的时候,Canvas 会检测整个代码定义的样式,如果在新的路径中没有定义样式,则会延用原来定义样式。

我们再来看一下这种情况:

js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 10;
  ctx.strokeStyle = "hotpink";
  ctx.moveTo(20, 30);
  ctx.lineTo(180, 30);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = 5;
  ctx.moveTo(20, 70);
  ctx.lineTo(180, 70);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = 15;
  ctx.moveTo(20, 120);
  ctx.lineTo(180, 120);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>
js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 10;
  ctx.strokeStyle = "hotpink";
  ctx.moveTo(20, 30);
  ctx.lineTo(180, 30);
  ctx.stroke();

  ctx.lineWidth = 5;
  ctx.moveTo(20, 70);
  ctx.lineTo(180, 70);
  ctx.stroke();

  ctx.lineWidth = 15;
  ctx.moveTo(20, 120);
  ctx.lineTo(180, 120);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>

当我们删掉 ctx.beginPath(); 时,三条线变成了一样的线宽,怎么回事呢?那是因为在同一个路径中,Canvas 会使用最后一次定义的样式,也就是说想使用不同的样式时,需要以开始一条新路(ctx.beginPath)径来重新定义线条的样式属性。

lineCap 属性

lineCap 属性用于显示线条开始处与结尾处线帽样式;

js 复制代码
ctx.lineCap = "Butt";
// 取值为: 
// "Butt": 默认值,无线帽
// "Round": 圆形线帽
// "Square": 方形线帽

对应的属性值大小写都可以,我们来用实际对比代码来看看这几个属性值有啥区别:

js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 1;
  ctx.strokeStyle = "#cccccc";
  ctx.moveTo(10, 0);
  ctx.lineTo(10, 150);
  ctx.moveTo(180, 0);
  ctx.lineTo(180, 150);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = 20;
  ctx.lineCap = "butt";
  ctx.strokeStyle = "hotpink";
  ctx.moveTo(10, 30);
  ctx.lineTo(180, 30);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineCap = "round";
  ctx.moveTo(10, 70);
  ctx.lineTo(180, 70);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineCap = "square";
  ctx.moveTo(10, 120);
  ctx.lineTo(180, 120);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>

我们可以从图片与代码中看到,"round" 和 "square" 的长度比 "butt" 更长,要长多少?从代码中我们能看到,长一个 lineWidth 的长度,两头平分,总结一下:有线帽的比没线帽的长一个线宽的长度

lineJoin 属性

在 Canvas 中,lineJoin 属性定义两个线条交接处的样式。

js 复制代码
ctx.lineJoin = "miter";
// 取值为: 
// "miter": 默认值,尖角
// "round": 圆角
// "bevel": 斜角

我们具体来看看 lineJoin 属性分别有什么区别:

js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 20;
  ctx.strokeStyle = "hotpink";

  ctx.beginPath();
  ctx.lineJoin = "miter";
  ctx.moveTo(10, 20);
  ctx.lineTo(180, 20);
  ctx.lineTo(180, 40);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineJoin = "round";
  ctx.moveTo(10, 70);
  ctx.lineTo(180, 70);
  ctx.lineTo(180, 100);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineJoin = "bevel";
  ctx.moveTo(10, 120);
  ctx.lineTo(180, 120);
  ctx.lineTo(180, 140);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>

从上图及代码中我们可以总结出三者的区别:

  • mitter: 线条直接延伸交于点,为默认值;
  • round:交接处是一个圆角,圆角所在圆直径等于线宽;
  • bevel:交接处是一个斜角,斜角所在正方形的对角线长等于线宽。

setLineDash() 方法

在 Canvas 中,用setLineDash() 方法来设置线条虚实样式。

js 复制代码
ctx.setLineDash(array);
// array 是一个数组组合

我们来看看具体怎么使用:

js 复制代码
<template>
  <canvas ref="cnv" width="200" height="150" style="border: 1px dashed gray"></canvas>
</template>

<script setup>
import {ref, onMounted} from "vue";
const cnv = ref();

const drawLine = () => {
  const ctx = cnv.value.getContext('2d');

  ctx.lineWidth = 2;
  ctx.strokeStyle = "hotpink";

  ctx.beginPath();
  ctx.moveTo(10, 20);
  ctx.lineTo(180, 20);
  ctx.setLineDash([2, 2]);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(10, 60);
  ctx.lineTo(180, 60);
  ctx.setLineDash([5, 5]);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(10, 80);
  ctx.lineTo(180, 80);
  ctx.setLineDash([10, 5]);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(10, 120);
  ctx.lineTo(180, 120);
  ctx.setLineDash([20, 5, 5, 5]);
  ctx.stroke();
}

onMounted(() => {
  drawLine();
});
</script>

从上面的图我们可以总结出参数的规则:

  • setLineDash() 方法接受一个整数数组;
  • 数组索引偶数为实线长度,奇数为虚线间隔距离;
  • 如果设置虚线绘制,即使使用 beginPath()方法也不能重置绘制的线为实线,需手动设置参数为[] 或 [num, 0]。

总结

本节内容很简单,主要就是针对线条的样式的设定,样式的设定给单调的线条有增多各种展示与应用的可能性。

相关推荐
国服第二切图仔19 分钟前
DevUI Design中后台产品开源前端解决方案之Carousel 走马灯组件使用指南
前端·开源
无限大626 分钟前
为什么浏览器能看懂网页代码?——从HTML到渲染引擎的奇幻之旅
前端
福尔摩斯张28 分钟前
Linux信号捕捉特性详解:从基础到高级实践(超详细)
linux·运维·服务器·c语言·前端·驱动开发·microsoft
2401_8603195231 分钟前
DevUI组件库实战:从入门到企业级应用的深度探索 ,如何快速安装DevUI
前端·前端框架
计算机毕设VX:Fegn089541 分钟前
计算机毕业设计|基于springboot + vue服装商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·课程设计
cc蒲公英1 小时前
javascript有哪些内置对象
java·前端·javascript
zhangwenwu的前端小站1 小时前
vue 对接 Dify 官方 SSE 流式响应
前端·javascript·vue.js
王林不想说话1 小时前
受控/非受控组件分析
前端·react.js·typescript
_杨瀚博1 小时前
VUE中使用AXIOS包装API代理
前端
张有志1 小时前
基于 Body 滚动的虚拟滚动组件技术实现
前端·react.js