模拟画板进行画点
方法:DIV
通过div来进行模拟画板
CSS
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#canvas {
border: 1px solid red;
height: 100vh;
}
</style>
body
<div id="canvas"></div>
JS
<script>
canvas.onmousemove = (e) => {
console.log(e.clientX)
console.log(e.clientY)
//console.log 调试大法 获取目标位置
let div = document.createElement('div')
div.style.position = 'absolute'
div.style.left = e.clientX + 'px'
div.style.top = e.clientY + 'px'
div.style.width = '6px'
div.style.height = '6px'
div.style.marginLeft = '-3px'
div.style.marginTop = '-3px'
div.style.borderRadius = '50%'
div.style.backgroundColor = 'black'
canvas.appendChild(div)
}
</script>
通过 console.log来获取鼠标点击时/鼠标移动时的位置信息
console.log(e.clientX)
console.log(e.clientY)
![079e2fa62274ef187f6cc680c87e3056.png](https://img-blog.csdnimg.cn/img_convert/079e2fa62274ef187f6cc680c87e3056.png)
![079e2fa62274ef187f6cc680c87e3056.png](https://img-blog.csdnimg.cn/img_convert/079e2fa62274ef187f6cc680c87e3056.png)
ü 通过let div = document.createElement('div')创建一个div元素
let div = document.createElement('div')
声明 文档(当前网页) 创建 元素/标签 ‘元素名’
含义:在文档中创建一个div标签,并且赋予给左边的div变量,这样我们可以直接通过变量(div)来调整样式
ü 在最后一定要添加 canvas.appendChild(div)
canvas.appendChild(div)
Id标签 添加 孩子 元素 注:不加引号‘’
给canvas(id)添加孩子div,只有这样div才能添加到HTML中去
默认所有的东西都是在内存中的,需要进行调用/添加才可进行使用
ü 通过div.style.position = 'absolute'首先设置div元素的层叠关系(位置)为absolut绝对定位(最上方)
回顾下div的层叠世界
ü 通过div.style.left = e.clientX + 'px'调整div的位置
div.style.top = e.clientY + 'px'
注意:一定要加+'px',不然只会在控制台显示,不会有像素的变化
ü 通过div.style.width = '6px'调制div的宽高比
div.style.height = '6px'
注:都需要加style,因为都是通过JS添加的CSS属性
ü 通过div.style.marginLeft = '-3px'调整div处于鼠标箭头的正中心
div.style.marginTop = '-3px'
![079e2fa62274ef187f6cc680c87e3056.png](https://img-blog.csdnimg.cn/img_convert/079e2fa62274ef187f6cc680c87e3056.png)
ü 通过div.style.borderRadius = '50%' 圆角(把矩形变成圆形)
![079e2fa62274ef187f6cc680c87e3056.png](https://img-blog.csdnimg.cn/img_convert/079e2fa62274ef187f6cc680c87e3056.png)
ü 通过div.style.backgroundColor = 'black' 填充颜色
注:Color可省略
ü 以上样式都是通过JS基于CSS样式属性上进行添加的,所有不要忘记添加stylep哦,
总结:以上操作都是通过JS操作DOM上添加节点,JS的单线程(重复一遍的执行)非常的慢,所有下面我们用更为方便的canvas来制作画板
Canvas
画点(矩形)
CSS
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
#canvas{
/* border: 1px solid red; */
display: block;
}
HTML
<canvas id="canvas"></canvas>
Js
<script>
let canvas = document.getElementById('canvas');
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
let painting = false;
canvas.onmousedown = (e) => {
painting = true;
}
canvas.onmousemove = (e) => {
if (painting === true) {
ctx.fillRect(e.clientX-5,e.clientY-5,10,10)
} else {
console.log('什么也不做')
}
}
canvas.onmouseup = () => {
painting = false;
}
</script>
注:canvas不是DIV,类似于img(在HTML设置宽高比,但在CSS中会覆盖原有尺寸,其优先级更高)
ü 通过ctx.fillStyle = 'black';//调整颜色
ü 通过 ctx.fillRect(e.clientX-5,e.clientY-5,10,10)控制矩形的样式
当canvas在HTML确定好尺寸,再通过CSS强行修改的,画板中元素会失真(被拉伸),类似于img;所以CSS中不能设置width/height;
Canvas的默认尺寸为inline(尽可能的窄),blcok(尽可能的宽)
我们就需要屏幕的大小(自适应)来决定
好的习惯:先进行网上查询,“JS 如何获取屏幕尺寸(宽高)”
通过console.log(document.documentElement.clientWidth)打印屏幕宽度
通过console.log(document.documentElement.clientHeight)打印屏幕高度
注意:不要通过document.body.clientHeight来获取 屏幕高度;body的高度是由其内容决定的,获取的是body的高度并不是屏幕(文档)的高度,所以要用document.documentElement.clientHeight
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
Canvas的width等于屏幕的宽
Canvas的Height等于屏幕的高
通过let painting = false; painting = false配合鼠标事件onmousemove/onmouseup来控制开启和停止画线
通过fillStyle控制填充的颜色
canvas不会通过Js新建DOM节点,只是告诉画板进行像素绘制,所以不会有延迟的出现
onmousedown为开启(绿灯)
painting=true
onmouseup为关闭(红灯)
painting=false
注意if(===){}一定时三个符号进行判断
消除锯齿并画圆形
<script>
let canvas = document.getElementById('canvas');
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
ctx.strokeStyle='none';
let painting = false;
canvas.onmousedown = (e) => {
painting = true;
}
canvas.onmousemove = (e) => {
if (painting === true) {
ctx.beginPath();
ctx.arc(e.clientX,e.clientY, 5, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
} else {
console.log('什么也不做')
}
}
canvas.onmouseup = () => {
painting = false;
}
</script>
通过ctx.arc(e.clientX,e.clientY, 5, 0, 2 * Math.PI)控制圆形的样式
通过 ctx.fill()调用之前声明fillStyle颜色
fill()方法填充当前图像(路劲),默认颜色为黑色
注:fillStyle属性用来填充另一种颜色/渐变
注:如果路径未关闭,那么fill()方法会以路径结束点到开始点添加一条线,以关闭路径,然后填充该路径
API在前端中含义
api全程为application interface(接口),前端所说的api,通常指的是JavaScript封装的一些功能
api可以理解为一个功能
function add(a,b){
return a+b;
}
//简单的求和api
疑问:function f(a){}中a是怎么来的
function fn(a){
console.log(a)
}
f(1)
f(2)
当声明一个函数和参数后,当别人调用的时候,传给a什么值就是什么值
onmousemove是怎么来的
当用户鼠标动的时候,浏览器会调用onmousemove,把canvas.onmousemove(事件相关信息)传回给你(包装成'e'),所以事件相关信息的取值什么都可以,最终用收到才会看见画线过程
注意:不可以在canvas标签上直接写width=100vw;height=100vh因为这是CSS单位,不是HTML的
拓展:querySelector()方法返回文档中批评为指定CSS选择器的一个元素
在移动端上调试
常识:手机上没有鼠标,所以要首先确定浏览器是否支持触屏(监听触屏事件)
var isTouchDevice = 'ontouchstart' in document.doucumentElement;
console.log(isTouchDevice) //声明后需要console.log测试下是否支持:移动端显示true;pc端显示false
CSS
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
#canvas{
/* border: 1px solid red; */
display: block;
}
HTML
<canvas id="canvas"></canvas>
Js
let canvas = document.getElementById('canvas');
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
let isTouchDevice = 'ontouchstart' in document.documentElement;
let painting = false;
// let last
if (isTouchDevice) {
canvas.ontouchmove = (a) => {
let x = a.touches[0].clientX;
let y = a.touches[0].clientY;
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
} else {
canvas.onmousedown = (e) => {
painting = true;
}
canvas.onmousemove = (e) => {
if (painting === true) {
ctx.beginPath();
ctx.arc(x,y,10,0,2*Math.PI)
ctx.stroke();
ctx.fill();
}
}
canvas.onmouseup = () => {
painting = false;
}
}
注意:移动端与PC端的不同,触摸手指个数。
可以通过console.log(e.touches[0])先确定是否可以获取x和y的值,console.log(x,y)可以包含两个数值
通过let x=e.toaches[0].clientX 和 let y=e.toaches[0].clientY 设置触摸的位置属性(x,y)
移动端会自动监听是否触摸开启和关闭。bug:在微信浏览器有bug,在向下划动时,屏幕会跟着动
画线
canvas mdn查阅资料
CSS
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
#canvas{
/* border: 1px solid red; */
display: block;
}
HTML
<canvas id="canvas"></canvas>
Js
let canvas = document.getElementById('canvas');
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'black';
ctx.lineWidth = 5;
ctx.lineCap = "round";
let isTouchDevice = 'ontouchstart' in document.documentElement;
let painting = false;
// let last
function drawline(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
if (isTouchDevice) {
canvas.ontouchstart = (a) => {
let x = a.touches[0].clientX;
let y = a.touches[0].clientY;
last = [x, y]
console.log(x, y);
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
}
canvas.ontouchmove = (a) => {
let x = a.touches[0].clientX;
let y = a.touches[0].clientY;
drawline(last[0], last[0], x, y)
last = [x, y]
}
} else {
canvas.onmousedown = (e) => {
painting = true;
last = [e.clientX, e.clientY]
}
canvas.onmousemove = (e) => {
if (painting === true) {
drawline(last[0], last[1], e.clientX, e.clientY);
last = [e.clientX, e.clientY];
} else {
console.log('什么也不做')
}
}
canvas.onmouseup = () => {
painting = false;
}
}
</script>
通过以下代码控制是否画线
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
通过写成一个函数drawLine(0,0,500,500)传四个参数来可以用来调用其代码
function drawline(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
通过let last 声明变量,用来表示记录上次的起点位置
通过设置第一个点(鼠标按下)
canvas.onmousedown = (e) => {
painting = true;
last = [e.clientX, e.clientY]
}
马上让上次位置等于这次位置(实施更新位置)
canvas.onmousemove = (e) => {
if (painting === true) {
drawline(last[0], last[1], e.clientX, e.clientY);
last = [e.clientX, e.clientY];
原理:当第3个点移动时,出现di3个点时,Js会诚信被调用一般,last=[e.clientX,e.clientY]则会把第2个点当作起始点,一次类推,这样就实现了画线(而不会出现始终从第一点开始的bug)
注:Js不会调用DOM,而是直接告诉canvas
注:last[0]是二位数组中的第一个元素,以此类推
通过ctx.lineWidth = 5控制线条粗心
通过ctx.lineCap = "round";控制两端为圆头
常识:注意凡是移动端都需要考虑几点触控(几个手指)
可以console.log获取位置信息(touches[0]是一个手指,一点触控)
console.log( a.touches[0].clientX)
console.log(a.touches[0].clientY)
移动端(触摸事件)
按下手指(第一次位置)
ontouchstart
拖拽/移动手指(第二次位置开始)
ontouchmove
完成触屏/结束(最后一次位置记录)
ontouchend
触屏取消
ontouchcancel(电话/弹出信息触发取消,一般会在ontouchcancel暂停/存档操作)
注:移动端默认移走手指则关闭关闭,所以不用设置
PC端(鼠标事件)
按下鼠标
onmousedown
移动鼠标
onmousemove
松开鼠标
onmouseup
移动到元素外
onmouseout
移动到指定元素
onmouseover
拓展:函数基本概念
函数声明
function fn() {}
使用function关键字声明一个函数,在指定一个函数名,叫做函数声明
函数表达式
var fnName= function(){}
使function关键字声明一个函数,但为给函数命名,最后将匿名函数赋予一个变量,叫做函数表达式,这也是最常见的函数表达式
注:匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则时间处理程序或创建闭包等等
函数声明和函数表达式不同之处在于
一、JavaScript引擎在解析 JavaScript代码时会函数声明提升当前执行环境(作用域)上的函数声明
而函数表达式必须等到JavaScript引擎执行到它所在的行时,才会从上而下一行一行的解析函数表达式
二、函数表达式后面可以加括号,立即调用该函数。函数声明不可以,只能以fnName()形式调用函数
在function前面加!、+、-甚至时逗号等都可以起到函数定义后立即执行的效果,而()、!、+、-、=等运算符,都将函数声明转换成函数表达式
消除了JavaScript引擎灯识别函数表达式和函数声明的歧义,告诉JavaScript引擎这是一个函数表达式,不是函数声明,可以在后面加括号,并立即执行函数的代码
举例:
function t1(age){
console.log(age); //2:收到传给参数后,打印23
var age=function age(){
console.log(age); //4:通过age()调用得到;注:此处age()中age为变量不是函数名
}
age();
console.log(age); //7:通过第7行console.log(age)打印得到,此处的age来说也是变量
}
t1(23);
________
23 //2
f age(){ //4
console.log(age);
}
f age(){ //7
console.log(age);
}