JavaScript全解析——canvas 入门(下)

news2024/12/22 16:37:02

canvas 线段两端的样式
●canvas 中, 是可以设置线段两端的样子的
●我们先来画三个平行线

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(100, 150)
ctx.lineTo(200, 150)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(100, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()


复制代码

●接下来, 我们开始设置两端样式
语法: 工具箱.lineCap = '值'
值 :
=> butt 无
=> round 圆
=> square 方

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 butt
ctx.lineCap = 'butt'

ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(100, 150)
ctx.lineTo(200, 150)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 round
ctx.lineCap = 'round'

ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(100, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 'square'
ctx.lineCap = 'square'

ctx.stroke()
ctx.beginPath()


复制代码

●square 和 round 会让线段稍稍变长
●线段端点样式的颜色会和线段颜色保持一致

canvas 线段拐点的样式
●canvas 在绘制线段拐角的时候, 会自动进行闭合拐角
●我们也可以通过设置, 来设置一下拐角的样子
●先来绘制三个带有拐角的线段

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 150)
ctx.lineTo(100, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(200, 100)
ctx.lineTo(300, 150)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(300, 100)
ctx.lineTo(400, 150)
ctx.lineTo(300, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()


复制代码

●canvas 对于线段拐点默认的样式就是尖角拐点
●我们可以进行一些设置来改变
语法: 工具箱.lineJoin = '值'
值:
=> miter 默认尖角拐点
=> round 创建圆角拐点
=> bevel 创建斜角拐点

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 150)
ctx.lineTo(100, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 默认拐点
ctx.lineJoin = 'miter'

ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(200, 100)
ctx.lineTo(300, 150)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 圆角拐点
ctx.lineJoin = 'round'

ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(300, 100)
ctx.lineTo(400, 150)
ctx.lineTo(300, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 斜角拐点
ctx.lineJoin = 'bevel'

ctx.stroke()
ctx.beginPath()


复制代码

canvas 填充
●在 canvas 中, 一旦你画出封闭图形以后
●我们不光可以描边, 也可以进行填充, 也就是填满颜色
●先来画一个矩形吧

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.closePath()
ctx.stroke()


复制代码

●我们这里用的是描边( 工具箱.stroke() )
●是按照痕迹把路线描绘下来
●在 canvas 内, 除了描边, 还有一个叫做填充
●咱们再来一个矩形, 这次我们不进行描边, 而是进行填充

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

// 3. 填充
// 语法: 工具箱.fill()
ctx.fill()



复制代码

●这样, 就会按照我们绘制的路线, 以填充的形式出现一个封闭图形
●注意 : 填充的时候可以不进行图形闭合, 会自动闭合图形以后进行填充
●填充的时候也可以设置填充颜色的设置

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

// 3. 填充
// 3-1. 填充颜色设置
// 语法: 工具箱.fillStyle = '值'
ctx.fillStyle = 'skyblue'
// 3-2. 填充
ctx.fill()


复制代码

●填充是可以和描边一起使用的

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

// 自动闭合图形
ctx.closePath()

// 3. 描边
// 3-1. 设置描边样式
ctx.lineWidth = 4
ctx.strokeStyle = 'orange'
// 3-2. 描边
ctx.stroke()

// 4. 填充
// 4-1. 填充颜色设置
ctx.fillStyle = 'skyblue'
// 4-2. 填充
ctx.fill()


复制代码

canvas 的填充规则
●我们发现, 到现在为止, canvas 的绘制, 描边, 填充都很简单
●但是接下来的内容可能稍微复杂一些了
●我们要说一下 canvas 的填充规则
●我们管 canvas 的填充规则叫做 非零填充

例子
●一下子可能说不明白, 我们先来看一个例子
●绘制一个 "回" 形
●注意一个细节 :
○我们绘制的过程
○里面的小正方形我们会按照 顺时针 的方向绘制
○外面的大正方形我们也会按照 顺时针 的方向绘制

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(300, 100)
ctx.lineTo(300, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
ctx.stroke()


复制代码

●两个正方形都是这个方向绘制的, 我们接下来把描边的线去掉
●我们来进行一下填充看看

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(300, 100)
ctx.lineTo(300, 200)
ctx.lineTo(200, 200)
// ctx.lineWidth = 2
// ctx.strokeStyle = '#000'
// ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
// ctx.stroke()

// 4. 填充
ctx.fill()


复制代码

●我们发现, 两个都被填充了
●这是因为, 在填充的时候, 就是会一次性把所有的内容都会填充好
●注意 :
○和是否闭合路径 ( 工具箱.closePath() ) 没有关系
○和里外正方形的绘制先后顺序没有关系
●那是怎么回事呢 ?

例子
●先不管是怎么回事, 我们再来看一个例子
●还是绘制一个 "回" 形
●注意一个细节 :
○我们绘制的过程
○里面的小正方形我们会按照 逆时针 的方向绘制
○外面的大正方形我们也会按照 顺时针 的方向绘制

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(300, 200)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
ctx.stroke()


复制代码

●这回两个矩形绘制的时候, 方向不一样了
●我们再来填充一次试试看

●我们会发现, 和刚才填充出来的结果不一样了
●这又是怎么回事呢 ?
●难道和顺时针逆时针有关系吗 ?

非零填充
●其实我们的填充和顺时针逆时针有关系, 但是不是简单的顺逆时针的问题
●概念 :
○从任何一个区域向画布最外层移动
○按照经历最短边计算
○其中经历的顺时针的边记录为 +1
○经历逆时针的边记录为 -1
○只要最终总和不为 零, 那么该区域填充
○如果最终总和为 零, 那么该区域不填充
●听起来很麻烦, 咱们来画布上看一下效果就好了
●这次我们绘制一个稍微复杂一些的图形

●这是两个矩形对接在一起, 一个是顺时针绘制, 一个是逆时针绘制
●我们来分析一下看看
●首先, 最左侧封闭图形

○如果走最短的路线出来的话, 会经历一条顺时针的边
○记录为 +1
○最终为 +1
○所以该区域填充
●然后, 最右侧封闭图形

○经历最短路线出来的话, 会经历一条逆时针的边
○记录为 -1
○最终为 -1
○所以该区域填充
●最后, 中间的封闭图形

○经历最短路线出来的会, 必然会经历一条顺时针的边和一条逆时针的边
○顺时针记录为 +1
○逆时针记录为 -1
○最终为 0
○所以该区域不填充
●此时我们对当前图形进行填充后观察

●这就是最后填充好的样子

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/489362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

webpack 5 实战(2)

二十一、babel-loader 使用 使用babel-loader对js文件进行处理,在lg.Webpack.js配置文件中配置js文件规则。 使用单独的插件进行转换 使用预设进行转换 使用babel.config.js配置文件进行babel配置 const path require(path) const CopyWebpackPlugin require(…

day12 IP协议与ethernet协议

目录 IP包头 IP网的意义 IP数据报的格式 IP数据报分片 以太网包头(链路层协议) IP包头 IP网的意义 当互联网上的主机进行通信时,就好像在一个网络上通信一样,看不见互联的各具体的网络异构细节; 如果在这种覆盖…

RabbitMQ 死信队列实现

// consumer处理成功后,通知broker删除队列中的消息,如果设置multipletrue,表示支持批量确认机制以减少网络流量 channel.basicAck(deliveryTag, multiple);// 拒绝deliveryTag对应的消息,第二个参数是否requeue,true则…

Inception模型实现孤立手语词的识别

实现孤立手语词的识别流程如下,在实际研究中,本章将着重研究第三阶段内容,也就是模型的设计与实现过程,目的是提高手语图像的识别准确率。 Inception模型实现 Inception模型是谷歌研究人员在2014年提出的一个深度卷…

网工Python:如何使用Netmiko的SCP函数进行文件传输?

在网络设备管理中,传输配置文件、镜像文件等是经常需要进行的操作。Netmiko是一个Python库,可用于与各种网络设备进行交互,提供了一些用于传输文件的函数,其中包括SCP(Secure Copy Protocol)函数。本文将介…

【软考备战·希赛网每日一练】2023年5月4日

文章目录 一、今日成绩二、错题总结第一题第二题第三题第四题三、知识查缺 题目及解析来源:2023年05月04日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析: 修改Linux文件权限命令:chmod。 第二题 解析: 第三题 解析…

欧拉奔赴品牌2.0时代,女性汽车真实用户需求被定义?

每年的上海国际汽车工业展览会,不仅是各大汽车品牌的技术“秀场”,也是品牌的营销“修罗场”。今年上海车展出圈的营销事件特别多,热度甚至一再蔓延到汽车行业外,其中欧拉也贡献了不少流量。 据了解,在2023上海车展欧…

mount disk space from SAN

mount disk from FC-SAN 配置硬盘域、存储池、LUN、主机及LUN与与主机之间的映射。 fc-san多路径范例1 fc-san多路径2 mount disk from iSCSI [rootqionghai11g ~]# iscsiadm -m discovery -t sendtargets -p 192.16.10.188:3260 Starting iscsid: [ OK ] 192.16.10.188:32…

Yolov1 源码讲解 voc.py

先看结构 1.mean_rgb是voc2007专用的均值 voc2007分别是这样的 坐标格式(X0,Y0,X1,Y1)其中X0,Y0是左上角的坐标,X1,Y1是右下角的坐标。 coco,voc ,yolo数据集中的bbox的坐标格式_coco bbox格式_十二耳环的博客-CSDN…

Jmeter之BeanShell取出需要参数,传递给下个请求

一、事件背景: 上周同事用Jmeter录制脚本,录制成功回放后,并没有达到自己想要的结果。 他的真实需求是,想从数据库取出某个字段值,然后对数据库做操作。 也就是想实现做参数传递的效果,我心痒痒的&#…

ConcurrentHashMap底层源码解析

ConcurrentHashMap线程安全,底层数组链表红黑树。 思想,分而治之。 JDK7有Segment对象,分段锁 JDK8没有了这个对象 总结, 首先计算hash, 如果集合没有元素,开始initTable方法初始化,这里扩容讲…

有人说ChatGPT信息不新?

Hello ,我是小索奇,今天给大家分享一个插件,这个插件可以通过抓取网页获得最新内容,它可以有效的避免ChatGPT信息过时,获取不到最新的信息等等 演示-这里问它一些问题: 现在几点了呀 可以看到时间也是很准确的&#x…

Linux权限(+Linux基本指令(下))

目录 一.基本指令补充 1.date指令 2.find指令 3.tar指令 4.Linux下的常用热键 二.Linux权限 1.Shell 2.Linux权限的概念 一.基本指令补充 1.date指令 😆date指令可以用于显示日期和时间戳😆Linux的时间戳与Unix时间戳一致,指的是从1970年1月1日…

使用无标注的数据训练Bert

文章目录 1、准备用于训练的数据集2、处理数据集3、克隆代码4、运行代码5、将ckpt模型转为bin模型使其可在pytorch中运用 Bert官方仓库:https://github.com/google-research/bert 1、准备用于训练的数据集 此处准备的是BBC news的数据集,下载链接&…

Python | 人脸识别系统 — UI界面设计

本博客为人脸识别系统的UI界面设计代码解释 人脸识别系统博客汇总:人脸识别系统-博客索引 项目GitHub地址:【待】 注意:阅读本博客前请先参考以下博客 工具安装、环境配置:人脸识别系统-简介 阅读完本博客后可以继续阅读&#xff…

不用下载就能使用的4款轻量在线PS工具

PS是一种非常熟悉的设计工具,也是一种在设计领域占有重要地位的软件,如常见的产品设计、平面设计或摄影后期设计,几乎与PS的使用密不可分。PS本身也有很多功能,每个人的日常设计图纸、图纸修复等工作都可以用PS完成。 但PS有很多…

yolov8 OpenCV DNN 部署 推理报错

yolov8是yolov5作者发布的新作品 目录 1、下载源码 2、下载权重 3、配置环境 4、导出onnx格式 5、OpenCV DNN 推理 1、下载源码 git clone https://github.com/ultralytics/ultralytics.git 2、下载权重 git clone https://github.com/ultralytics/assets/releases/dow…

MySQL知识学习05(InnoDB存储引擎对MVCC的实现)

1、一致性非锁定读和锁定读 一致性非锁定读 对于 一致性非锁定读(Consistent Nonlocking Reads) ,通常做法是加一个版本号或者时间戳字段,在更新数据的同时版本号 1 或者更新时间戳。查询时,将当前可见的版本号与对…

K8S资源-configmap创建六种方式

云原生实现配置分离重要实现方式 两者都是用来存储配置文件,configmap存储通用的配置文件,secret存储需要加密的配置文件。 将配置文件configmap挂在到pod上 创建configmap 1.基于配置文件目录创建configmap kubectl create cm cmdir --from-fileconf…

医学图像分割之U-Net

一、背景及问题 在过去两年中,在很多视觉识别任务重,深度卷积网络的表现优于当时最先进的方法。但这些深度卷积网络的发展受限于网络模型的大小以及训练数据集的规模。虽然这个限制有过突破,也是在更深的网络、更大的数据集中产生的更好的性能…