初识canvas
绘制三角形
useEffect(()=>{
if(canvasRef.current){
const ctx = canvasRef.current.getContext('2d')
// 定位开始点
ctx?.moveTo(30, 30)
//拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中),还没上色。
ctx?.lineTo(30, 90)
ctx?.lineTo(60,60)
//ctx?.lineTo(30,30)
// 形成闭合点,关闭当前的路径
ctx?.closePath()
//绘制
ctx?.stroke()
},[])
return <div>
<canvas ref={canvasRef} height={800} width={1240} style={{border: '1px solid #eee'}}></canvas>
</div>;
关键语法:
//获取画布元素
canvasRef.current
// 获取画布的工具集,可以🌹直线,圆等等。
const ctx = canvasRef.current.getContext('2d')
// 定位开始点(将点移动到30,30的位置,但是不会绘制出来。)
ctx.moveTo(30,30)
//拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中)
ctx?.lineTo(30, 90)
// 闭合点
ctx?.closePath()
//调用stroke才是真正绘制
ctx?.stroke()
绘制不同线条颜色的三角形。
//线条颜色
ctx!.strokeStyle = "red"
//线条宽度
ctx!.lineWidth = 10
- 重置路径:开始一条路径,切换与上一个图形的联系。可以实现不同大小和颜色图形的单独绘制
//线条宽度
ctx!.lineWidth = 5;
//线条颜色
ctx!.strokeStyle = "red";
// 定位开始点
ctx?.moveTo(30, 30);
//拖动,从第一个点移动到第二个点,只是描绘路径,(保存内存当中),还没上色。
ctx?.lineTo(30, 90);
//绘制
ctx?.stroke();
// 绘制完毕断开联系
ctx?.beginPath();
//绘制第二条线的起始点
ctx?.moveTo(30, 90);
ctx?.lineTo(60, 60);
ctx!.strokeStyle = "blue";
//绘制
ctx?.stroke();
// 绘制完毕断开联系
ctx?.beginPath();
//绘制第三条线的起始点
ctx?.moveTo(60, 60);
ctx?.lineTo(30, 30);
ctx!.strokeStyle = "yellow";
ctx?.stroke();
没描绘一条线的路径就直接绘制,然后调用beginPath断开联系,然后重新绘制起始点,继续绘制第二条线。
其他绘制的api
文字
//文字的绘制 font可以绘制样式
ctx!.font = "bold 32px 黑体"
//填充式
ctx?.fillText('哈哈哈', 100, 100)
// 描边
ctx?.strokeText("哈哈哈", 200, 200);
// // 文字的绘制 font可以绘制样式
ctx!.font = "bold 32px 黑体";
//以文字绘制的坐标为坐标轴起点,如以30,30位坐标轴原点,水平对齐
ctx!.textAlign = "left" ;
ctx!.textBaseline = 'top'
// 垂直对齐
ctx?.fillText("哈哈哈", 30, 30);
textAlign,水平对齐,以30,30的y轴,right表示在右边。
textBaseLine,垂直对齐,以30,30的x轴,top表示轴在上方。
toDataURL
canvas.toDataURL()
转为base64字符串。
const imgUrl = canvasRef.current.toDataURL("image/png",1)
绘制矩形圆形及图片。
- 矩形,先描边,再绘制。
// 矩形, x,y,width,height
ctx?.rect(100,100,100,100)
// 绘制或者填充
//ctx?.stroke()
ctx?.fill()
一次性。
//调用一次性
ctx?.strokeRect(200,200, 100,100)
清除内容。
ctx?.clearRect(190,190,120,120)
从190,190,开始,width 120,height 120清除内容。
- 圆形
///200,200 , 半径30, 从0度开始移动到360度,顺时针
ctx?.arc(300,300, 30, 0, Math.PI * 2 )
ctx?.stroke()
- 图片
const img = document.createElement('img')
img.src = png
img.onload=()=>{
//图片element, x, y, 图片w, 图片h
ctx?.drawImage(img, 200, 200, 100, 100)
const imgUrl = canvasRef.current!.toDataURL("image/png",1)
console.log('imgUrl',imgUrl);
setImgUrl(imgUrl)
}
放大
// element, x1,y1,w1,h1, x2,y2,w2,h2
ctx?.drawImage(img, 400,0, 500,500, 200,200, 100,100)
图片element, 图片x400,y0,图片400,0出发截取x轴500,图片400,0出发截取y轴500。
绘制到画布
200,200,高度200,宽度200
实现刮刮卡效果
const { width, height } = canvasRef.current;
//绘制
const arrGifs = ["一等奖", "二等奖", "未中奖"];
const text = arrGifs[Math.floor(Math.random() * arrGifs.length)];
ctx!.font = "bold 35px 黑体";
ctx!.textAlign = "center";
ctx!.textBaseline = "middle";
ctx!.fillStyle = "red";
ctx?.fillText(text, width / 2, height / 2);
const imgUrl = canvasRef.current.toDataURL("image/png", 1);
canvasRef.current.style.background = `url(${imgUrl})`;
//擦除元素
ctx?.clearRect(0, 0, width, height);
//绘制矩形 盖住信息
ctx!.fillStyle = "#999";
ctx?.fillRect(0, 0, width, height);
// 鼠标划擦,实现画布区域
let isDrag = false;
canvasRef.current.addEventListener("mousedown", () => {
isDrag = true;
//将绘制的区域置为透明
ctx!.globalCompositeOperation = "destination-out"
});
canvasRef.current.addEventListener("mousemove", (e) => {
if (isDrag) {
const { clientX: x, clientY: y } = e;
ctx!.fillStyle = "red";
ctx?.fillRect(x, y, 20, 20);
}
});
canvasRef.current.addEventListener("mouseup", () => {
isDrag = false;
});
主要分为三部分,
- 随机生成文字,转成base64,切成背景图存放。
- 使用灰色覆盖整个canvas
- 监听鼠标事件,鼠标经过哪绘制一个小的正方形,并且设置透明。这样就可以看到中奖文字。
效果:
three.js电子书
对webgl的封装。
three.js要素
- 渲染器 可以理解成电视机
new Three.WebGLRenderer({antialias: true})
- 场景 可以理解成拍电影时候的场景
const scene = new Three.Scene()
- 相机 可以理解成摄影机
透视相机,跟人的眼睛类似
const camera = new Three.PerspectiveCamera(100,狂高比,0.1, 100)
正交相机
new Three.OrthographicCamera(
window.innerWidth / -50, //相机左边范围
window.innerWidth / 50, //相机右边范围
window.innerHeight / 50, //相机上边范围
window.innerHeight / -50, //相机下边范围
0, //远近
5000 //远处的大小
);
- 几何体 可以理解成演员,需要放入到特定的场景
//创建一个几何体
//几何体宽高 宽,高,深度
const geomerty = new Three.CubeGeometry(4, 2, 4);
//材质 不反射光
const materital = new Three.MeshLambertMaterial({ color: "#eee" });
const cube = new Three.Mesh(geomerty, materital);
//将几何体放入场景
scene.add(cube)
- 光照, 可以理解成拍照片或者电影时候的补光,也需要放入特定的场景
//来点光照
const dirctionalLight = new Three.DirectionalLight("#fff", 1.1);
dirctionalLight.position.set(3, 2, 1);
scene.add(dirctionalLight);
相机获取场景内显示的内容,通过渲染器渲染到画布上去。
基本用法
//初始化场景
const scene = new Three.Scene(); //实例化场景
//初始化相机 参数: 人视野的范围,全景宽高比,近裁面(离人眼最近的距离),远裁面(离人眼最远的距离)
const camera = new Three.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
200
);
camera.position.set(0, 0, 15);
//创建一个几何体
//几何体宽高 宽,高,深度
const geomerty = new Three.CubeGeometry(4,2,4)
//材质 不反射光
const materital = new Three.MeshBasicMaterial({color: '#fff'})
// 通过立体+材质创建了一个几何体
const cube = new Three.Mesh(geomerty, materital)
//将几何体放入场景
scene.add(cube)
//初始化渲染器
//渲染器 antialias抗锯齿,渲染器渲染出来的就是canvas标签,需要插入documetn上
const renderer = new Three.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//渲染,放入场景和相机
renderer.render(scene, camera )
- 初始化一个场景
- 初始化一个相机,目前我们使用的是透视相机,他的位置在
这种比较符合人的眼睛
除此自外还有一种正交相机。
他的坐标轴跟几何体是一样的。 - 设置相机的位置。camera.position.set(4, 2, 6);xyz轴。
这就是相机的坐标轴(右手坐标系),如果设置0,0,6,那么他只看到z那一面
。设置了426之后
有点立体的效果了。
- 创建一个几何体
- 将几何体放入相机
- 初始化渲染器,并将渲染器渲染出的canvas插入document
- 将场景和相机放入渲染器
//初始化场景
const scene = new Three.Scene(); //实例化场景
//初始化相机 参数: 人视野的范围,全景宽高比,近裁面(离人眼最近的距离),远裁面(离人眼最远的距离)
const camera = new Three.PerspectiveCamera(
100,
window.innerWidth / window.innerHeight,
0.1,
200
);
// 设置相机
camera.position.set(4, 2, 6);
//创建一个几何体
//几何体宽高 宽,高,深度
const geomerty = new Three.CubeGeometry(4, 2, 4);
//材质 不反射光
const materital = new Three.MeshLambertMaterial({ color: "#eee" });
const cube = new Three.Mesh(geomerty, materital);
//将几何体放入场景
scene.add(cube);
//来点光照
const dirctionalLight = new Three.DirectionalLight("#fff", 1.1);
dirctionalLight.position.set(3, 10, 5);
// 光照也需要放入场景
scene.add(dirctionalLight);
//初始化渲染器
//渲染器 antialias抗锯齿,渲染器渲染出来的就是canvas标签,需要插入documetn上
const renderer = new Three.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, window.innerHeight);
document.body.appendChild(renderer.dom Element);
//渲染,放入场景和相机
renderer.render(scene, camera);
新增一些光照,并且几何体的材质改成反光的。
可以看到比较明显的立体感。
动画效果:不断地移动相机就行
let index = 8;
function render() {
index -= 0.1;
if (index > -8) {
console.log(123123);
camera.position.set(index, 2, 6);
//改完坐标需要重新渲染
renderer.render(scene, camera);
requestAnimationFrame(render);
}
}
render();
以上我们就基于three.js完成了一个小的demo.
总结:
three.js三要素,场景,相机,渲染器。
可以创建几何体并且设置大小,放入场景。
相机必须调整好位置,做好拍照准备。
然后将场景和相机放入渲染器(renderer.render(xx,xx)),相机就会根据自身位置以及场景内容“拍照”,最终反映到渲染器的canvas元素,将其插入dom中即可看到。