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

news2024/11/25 3:01:07

●canvas 是 HTML5 新增的一个标签, 表示画布
●canvas 也是 h5 的画布技术, 我们通过代码的方式在画布上描绘一个图像

canvas 标签
●向进行 canvas 绘图, 首先我们先要了解到 canvas 标签
●是 html5 推出的一个标签

<html>
<head>
    ...
</head>
<body>
    <canvas></canvas>
</body>
</html>


复制代码

○canvas 默认是一个行内块元素
○canvas 默认画布大小是 300 * 150
○canvas 默认没有边框, 背景默认为无色透明

canvas 画布大小
●我们在绘图之前, 先要确定一个画布的大小
○因为画布默认是按照比例调整
○所以我们调整宽度或者高度的时候, 调整一个, 另一个自然会按照比例自己调整
○我们也可以宽高一起调整
●调整画布大小有两种方案
○第一种 : 通过 css 样式 ( 不推荐 )

<html>
<head>
    <style>
        canvas {
            width: 1000px;
            height: 500px;
        }
    </style>
</head>
<body>
    <canvas></canvas>
</body>
</html>


复制代码

○第二种 : 通过标签属性 ( 推荐 )

<html>
<head>
    ...
</head>
<body>
    <canvas width="1000" height="500"></canvas>
</body>
</html>


复制代码

●两种方案的区别
○通过 css 样式的调整方案, 不推荐
是因为这个方案其实并没有设置了画布的大小
而是把原先 300 * 150 的画布, 将他的可视窗口变成了 1000 * 500
所以真实画布并没有放大, 只是可视程度变大了
举个例子 : 就是你把一个 300 * 150 的图片, 放大到 1000 * 500 的大小来看
所以这个方式我们及其不推荐

○通过属性的调整方案, 推荐
这个才是真正的调整画布的的大小
也就是我们会在一个 1000 * 500 的画布上进行绘制

●画布的坐标
○canvas 画布是和我们 css 的坐标系一样的
○从 canvas 的左上角为 0 0 左边, 分别向右向下延伸为正方向

canvas 初体验
●准备工作已经完成了, 我们可以开始体验一下绘制了
●其实 canvas 画布很简单, 就和我们 windows 电脑的画板工具是一样的道理

●思考 :
我们在 windows 这个画板上绘制内容的时候
我们一定是先选定一个工具 ( 画笔, 矩形, 圆形, ... )
设定好样式 ( 粗细, 颜色 )
然后开始绘制
●其实在 canvas 绘制也是一个道理
拿到一个画布工具箱
从工具箱中选定工具
设定样式
开始绘制
●初体验步骤
●index.html

<html>
<head>
    ...
</head>
<body>
    <canvas id="canvas" width="600" height="300"></canvas>
    
    <script src="./index.js"></script>
</body>
</html>


复制代码

●index.js

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

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

// 2. 开始绘制
// 2-1. 讲画笔移动到一个指定位置开始下笔
// 语法: 工具箱.moveTo(x轴坐标, y轴坐标)
ctx.moveTo(100, 100)

// 2-2. 将笔移动到一个指定位置, 画下一条轨迹
// 注意: 这里是没有显示的, 因为只是画了一个轨迹
// 语法: 工具箱.lineTo(x轴坐标, y轴坐标)
ctx.lineTo(300, 100)

// 2-3. 设定本条线的样式
// 设定线的宽度
// 语法: 工具箱.lineWidth = 数字
ctx.lineWidth = 10
// 设定线的颜色
// 语法: 工具箱.strokeStyle = '颜色'
ctx.strokeStyle = '#000'

// 2-4. 描边
// 把上边画下的痕迹按照设定好的样式描绘下来
// 语法: 工具箱.stroke()
ctx.stroke()


复制代码

●至此我们的第一个线段就绘制完毕, 画布上就会出现一条线段
○从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )
○线段长度为 200px
○线段宽度为 10px
○线段颜色为 '#000' ( 黑色 )

canvas 线宽颜色问题
●刚才我们经过了初体验, 画了一个线段
●看似没有问题, 也出现了线段, 但是其实内在是有一些问题的
●我们先来观察
●这次我们再来画一个线段
○从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )
○线段长度为 200px
○线段宽度为 1px
○线段颜色为 '#000' ( 黑色 )

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

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

// 2. 开始绘制
ctx.moveTo(100, 100)

// 2-2. 将笔移动到一个指定位置, 画下一条轨迹
ctx.lineTo(300, 100)

// 2-3. 设定本条线的样式
// 设定线的宽度
ctx.lineWidth = 10
// 设定线的颜色
ctx.strokeStyle = '#000'

// 2-4. 描边
ctx.stroke()


复制代码

●效果出现了, 没有什么问题
●只是看上去不太想 1px, 而且颜色有些浅
●不着急, 我们再来画一个线段
○从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )
○线段长度为 200px
○线段宽度为 2px
○线段颜色为 '#000' ( 黑色 )

●这个时候问题就出现了
○两次画出来的线段, 一次设置 1px 一次设置 2px
○感觉上 线宽度 一样
○两次画出来的线段, 两次都是设置为 '#000' 的颜色
○但是感觉上颜色不太一样

●这是因为浏览器在描述内容的时候, 最小的描述单位是 1px
●我们来模拟一下浏览器绘制的内容
○假设这是我们浏览器描述的画布中的像素点

○我们来做一个坐标的标记

○现在呢不关注线的长度和坐标, 我们就画一个宽度为 1px 的线段

○我们来剖析一下问题
因为在描绘这个线段的时候, 会把线段的最中心点放在这个像素点位上
也就是说, 在描述线宽的时候, 实际上会从 0.5px 的位置绘制到 1.5px 的位置
合计描述宽度为 1px
但是浏览器的最小描述为 1px
这里说的不是最小宽度为 1px, 是浏览器不能在非整数像素开始描述
也就是说浏览器没办法从 0.5 开始绘制, 也没有办法绘制到 1.5 停止
那么就只能是从 0 开始绘制到 2
所以线宽就会变成 2px 了
因为本身一个像素的黑色被强制拉伸到两个像素宽度, 所以颜色就会变浅
就像我们一杯墨水, 倒在一个杯子里面就是黑色
但是到在一个杯子里面的时候, 又倒进去一杯水, 颜色就会变浅
○实际描绘出来的样子

○这就变成了我们刚才看到的样子
●所以, 我们在进行 canvas 绘制内容的时候, 涉及到线段的时候
●我们一般不会把线段宽度设置成奇数, 一般都是偶数的

canvas 绘制平行线
●刚才我们绘制了线段, 接下来我们来绘制一个平行线, 也就是两个线段
●小伙伴: " 一个简单的效果, 想到就搞 "

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

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

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

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


复制代码

●没有问题, 效果实现了

●接下来, 咱们稍微增加一下需求
○第一个线段线宽 2px, 黑色
○第二个线段线宽 10px, 红色
●这也简单啊, 稍微修改一下

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

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

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

// 3. 开始绘制第二个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.stroke()


复制代码

●这是什么鬼, 为什么两个线段都变了, 不是应该只改变一个吗 ?
这是因为我们并没有告诉他这是两个不一样的线段
所以在设置线段样式的时候, 会默认按照最后一次设置的样式来绘制所有的线段
我们要想让第一个线段绘制完毕以后, 和第二个没有关系
我们需要告诉画布, 我的这个线段结束了, 后面的不要和我扯上关系

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

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

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

// 3. 结束之前的绘制内容
// 语法: 工具箱.beginPath()
ctx.beginPath()

// 4.. 开始绘制第二个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.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, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.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.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.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)

// 自动闭合图形
// 语法: 工具箱.closePath()
ctx.closePath()

ctx.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.stroke()


复制代码

●这个时候, 我们发现一个正常的三角形就出现了
●注意 : 闭合路径
closePath() 这个方法
是从当前坐标点, 直接用线段的方式连接到 modeTo() 的位置
也就是从当前坐标点直接连接到开始坐标点

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

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

相关文章

mysql详细教程

目录 1、初识数据库 1.1、什么是数据库 1.2、数据库分类 1.3、相关概念 1.4、MySQL及其安装 1.5、基本命令 2、操作数据库 2.1、操作数据库 2.2、数据库的列类型 2.3、数据库的字段属性 2.4、创建数据库表 2.5、数据库存储引擎 2.6、修改数据库 3、MySQL数据管理…

基于numpy的鸢尾花数据获取、处理等操作。

这是搬运的。 Python 3 可信的 FileEditViewInsertCellKernelHelp 运行 代码标记原生 NBConvert标题- 《基于numpy的鸢尾花数据操作》 一、 实验准备 1.1 实验概述 我们本次实验将会使用的编程语言是Python&#xff0c;在本次实验当中我们将会使用结合我们学习过的numpy 中的知…

SPSS如何进行判别分析之案例实训?

文章目录 0.引言1.一般判别分析2.逐步判别分析3.决策树分析 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;本文对判别分析进行阐述。 1…

Mysql Sql 优化之 Explain

在开发中&#xff0c;往往遇到一些慢查询语句&#xff0c; 我们需要对慢查询进行优化。Explain工具就是用来分析某个慢查询执行情况的工具。通过在select 语句前加上explain 关键字&#xff0c;然后执行就会得到某个sql 执行计划信息&#xff0c;通过分析执行计划&#xff0c;我…

JavaWeb:JavaScript 教程 笔记

1 JavaScript html完成了架子&#xff0c;css做了美化&#xff0c;但是网页是死的&#xff0c;我们需要给他注入灵魂&#xff0c;所以接下来我们需要学习JavaScript&#xff0c;这门语言会让我们的页面能够和用户进行交互。 1.1 介绍 通过代码/js效果演示提供资料进行效果演…

SettingsProvider单编生效

SettingsProvider单编生效 1、单编SettingProvider, make SettingsProvider&#xff0c;会生成apk&#xff0c;apk的路径为&#xff1a; product/qssi/system/priv-app/SettingsProvider/2、将手机恢复出厂设置&#xff0c;在过google向导之前 3、删除SettingProvider对应的…

【Redis】Redis分布式锁的10个坑

文章目录 前言1. 非原子操作&#xff08;setnx expire&#xff09;2.被别的客户端请求覆盖&#xff08; setnx value为过期时间&#xff09;3. 忘记设置过期时间4. 业务处理完&#xff0c;忘记释放锁5. B的锁被A给释放了6. 释放锁时&#xff0c;不是原子性7. 锁过期释放&…

复杂系统层级原理与模型驱动软件体系结构

最近看到模型驱动在国内渐渐被更多的人注意&#xff0c;前几天又看到一些关于UML优劣和应用方面的争论。作为繁忙工作中的一种休息&#xff0c;从过往的研究笔记中整理一点东西放在这里&#xff0c;与大家交流。 层级理论是构建复杂软件体系的基本原则 诺贝尔奖获得者赫伯特 A.…

RocketMQ第三节(生产者和消费者)

目录 1&#xff1a;生产者&#xff08;同步、异步、单向&#xff09; 1.1&#xff1a;同步发送消息&#xff08;每发送一条等待mq返回值&#xff09; 1.2&#xff1a;异步发送消息 1.3&#xff1a;单向发送消息&#xff08;不管成功失败&#xff0c;只管发送消息&#xff09…

学会以下几点,拍出人像大片很简单

很多人拍照&#xff0c;都是用手机拍的&#xff0c;虽然手机的摄影功能并没有相机那么齐全&#xff0c;但我们依然可以借助一些技巧拍出美美的照片&#xff0c;下面是为大家整理出了一份手机拍照指南&#xff0c;拍出人像大片很简单。 1、捕捉光影 光影是拍照的重要元素之一&…

【Unity编辑器】拓展Inspector视图

目录 1、拓展源生组件 2、拓展继承组件 3、组件不可编辑 4、Context菜单 1、拓展源生组件 摄像机就是典型的源生组件。它的局限性就是拓展组件只能加在源生组件的最上面或者最下面&#xff0c;不能插在中间&#xff0c;不过这样也就够了 using UnityEngine; using UnityEd…

接口测试之Jmeter+Ant+Jenkins接口自动化测试平台

目录 平台简介 环境准备 Jenkins简介 下载与安装 平台搭建 依赖文件配置 build.xml配置 Ant构建 阿里大佬倾情演绎&#xff0c;3天让你学会Jmeter接口测试&#xff0c;学不会算我输_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Q84y1K7bK/?spm_id_from333.99…

如何设置渗透测试实验室

导语&#xff1a;在本文中&#xff0c;我将介绍设置渗透实验室的最快方法。在开始下载和安装之前&#xff0c;必须确保你使用的计算机符合某些渗透测试的要求&#xff0c;这可以确保你可以一次运行多个虚拟机而不会出现任何问题。 在本文中&#xff0c;我将介绍设置渗透实验室的…

Python | 人脸识别系统 — 用户操作

本博客为人脸识别系统的摄像头画面展示代码解释 人脸识别系统博客汇总&#xff1a;人脸识别系统-博客索引 项目GitHub地址&#xff1a; 注意&#xff1a;阅读本博客前请先参考以下博客 工具安装、环境配置&#xff1a;人脸识别系统-简介 UI界面设计&#xff1a;人脸识别系统-UI…

错题汇总03

1.以下对二维数组a进行正确初始化的语句是 A int a[2][]{{0,1,2},{3,4,5}} B int a[][3]{{0,1,2},{3,4,5}} C int a[2][4]{{0,1,2},{3,4},{5}}; D int a[][3]{{0,,2},{},{3,4,5}} A数组列不能省略 C数组越界 D数组初始化每一行必须连续初始化 2.能把函数处理结果的二个数据…

msvcr110.dll丢失的解决方法-计算机中丢失msvcr110.dll怎么办?

看到您遇到了msvcr110.dll丢失的问题&#xff0c;这是由于您的计算机缺少必要的系统文件导致的。为了解决这个问题&#xff0c;您可以尝试以下几个步骤方法&#xff1a;就可以轻松解决msvcr110.dll丢失的问题。 msvcr110.dll修复方法一 重新安装Microsoft Visual C msvcr110.d…

windows安装node.js和vue3.x

目录 下载并安装node配置环境变量配置淘宝镜像源安装webpack全局打包工具安装cnpm安装vue-cli 3.xcnpm问题警告的解决办法 下载并安装node 1&#xff0c;下载nodejs 直接从node.js官网下载&#xff1a;https://nodejs.org/en/download 根据自己电脑的版本选择32位或者64位&…

建筑诊断用热像仪应用-flir T530红外热成像仪

建筑诊断用热像仪应用-flir T530红外热成像仪 建筑诊断领域热成像技术 隔热性能不良或隔热性能不足、潮气、建筑物外表面裂缝及不达标工程往往使住宅用建筑及商用建筑业主蒙受巨大的 经济损失。而红外热像仪却能够帮助您快速察觉有待改进的能效问题 建筑诊断用热像仪应用|带电…

两分钟成为 ChatGPT 国内高手【不要再拿ChatGPT当百度用了】

不要再问ChatGPT那些问百度的问题了&#xff0c;有更进阶的用法 更高效的编写prompts&#xff0c;以便ChatGPT给出更精准的回答 但是需要注意的是&#xff1a;国内现在根本没有GPT-4使用&#xff0c;但凡是说有GPT-4的都是骗子。 GPT 可以写文章&#xff0c;可以写诗&#x…

全方位揭秘!大数据从0到1的完美落地之运行流程和分片机制

一个完整的MapReduce程序在分布式运行时有三类实例进程&#xff1a; MRAppMaster: 负责整个程序的过程调度及状态协调MapTask: 负责Map阶段的整个数据处理流程ReduceTask: 负责Reduce阶段的整个数据处理流程 当一个作业提交后(mr程序启动)&#xff0c;大概流程如下&#xff1…