生活中有看到一个对称图案,看着很美,于是想到,试试用Canvas试着画对称图形来,想到就做,自己还真捣鼓出来了,自己弄了好多的对称图这里就不晒出来了,接下来讲讲怎么做,有兴趣的同学可以自己边学边动手做,瞧瞧谁做得对称图形最好看呢。
1. 页面设计
要做出一个好作品,是需要熟悉对“Canvas”的操作经验的,理清好思路和制作步骤,然后设计出页面,一个页面文件代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>对称图 Symmetric graph</title>
</head>
<body>
<canvas id="canv1" style="border: 1px solid #ccc;"></canvas>
<img id="output_img"/>
<script type="module">
import SymmetricGraph from './symmetric_graph.js';//引入模块
window.onload=()=>{
//...加载脚本
}
</script>
</body>
</html>
2. 编写脚本
接着,写好加载脚本,代码如下,别看代码少,建议学一学,原本很多行代码就变成这样一行代码了
const doms = {};
['canv1','output_img'].map(id=>[id,document.getElementById(id)]).forEach(args=>doms[args[0]]=args[1]);
const { canv1,output_img } = doms;
//创建模块对象
let sg = new SymmetricGraph(canv1,output_img);
//设置对象的配置
sg.setConfig({
lineWidth:5,//线条宽
strokeStyle:'#f00',//线条颜色
count:7,//复制图形的数量
});
3. 编写模块
上面发现了吗,加载的脚本中,有个对象类SymmetricGraph
是哪里来的,发现缺少引用的模块文件symmetric_graph.js
,接下来,我们就新建这一个模块
1. 初始化
模块文件的代码如下,先写好初始化逻辑,还有鼠标键的监听处理
export default class SymmetricGraph{
#size;
#ctx;
#ctxV;
#count=4;
constructor(canv1,output_img){
const ctx = canv1.getContext('2d');
const { width, height } = ctx.canvas;
const size = Math.max(width,height);
const canvasV = document.createElement('canvas');
canvasV.width=size;
canvasV.height=size;
const ctxV = canvasV.getContext('2d');
ctx.canvas.width=size;
ctx.canvas.height=size;
//保存需要读取的设置
this.#size=size;
this.#ctx=ctx;
this.#ctxV=ctxV;
//默认设置
this.setConfig();
let pointes = [];
//鼠标键按下时的处理
canv1.addEventListener('mousedown',(e)=>{
const { x, y } = e;
pointes.push({x,y});
ctx.beginPath();
ctx.moveTo(x,y);
});
//鼠标键按下并移动时的处理
canv1.addEventListener('mousemove',(e)=>{
if(pointes.length<=0) return;
const { x, y } = e;
ctx.lineTo(x,y);
ctx.stroke();
this.drawImage(ctx.canvas.toDataURL(),this.#count);
});
//鼠标键松开时的处理
canv1.addEventListener('mouseup',(e)=>{
const { x, y } = e;
pointes.length=0;
});
}
//设置配置
setConfig(e={}){
const config={
lineWidth:2,
strokeStyle:'#250',
backgroundColor:'#fff',
count:4,
};
Object.assign(config,e);
const ctx = this.#ctx;
ctx.lineWidth=config.lineWidth;
ctx.strokeStyle=config.strokeStyle;
this.#ctxV.fillStyle=config.backgroundColor;
this.#count=config.count;
}
//主要方法,绘制多个复制的图形
drawImage(src,count=4){
//...这里省略,下一步接着讲
}
}
2. 主要方法
将到重点,这是绘制图像的方法drawImage()
,传入两个参数,分别时要复制的图像src
,和复制数量count
,仔细看下代码,会发现很简单
let img = new Image();
img.onload=()=>{
const size = this.#size;
const s = size*0.5;
const ctx = this.#ctxV;
const max = 360;
let offset = max/count;
//填充画布背景
ctx.rect(0,0,size,size);
ctx.fill();
//旋转不同角度,再绘制图形
for(let i=0; i<max; i+=offset){
ctx.save();
ctx.translate(size/2,size/2);
ctx.rotate(i/180*Math.PI);
ctx.translate(-size/2,-size/2);
ctx.drawImage(img,(size-s)/2,0,s,s);
ctx.restore();
}
//将绘制好的图案设置到图像标签中,显示出来
output_img.setAttribute('src',ctx.canvas.toDataURL());
//清空画布
ctx.clearRect(0,0,size,size);
};
img.src=src;
4. 运行测试
很快收工了,写得代码不多,没有问题的话,就用浏览器打开网页,试着在画布上用鼠标按下,随意画,就会看到生成漂亮的图案了,鼠标右键可保存下来,这个用途有很多的,能想到的是,可以用在刻印上,或者当作纹理图案素材,最后,附上录制的效果图
💡试试修改页面脚本中的如下配置,可以绘制很多不一样的图案哦
sg.setConfig({
lineWidth:5,//线条宽
strokeStyle:'#f00',//线条颜色
count:7,//复制图形的数量
});