赵工的个人空间


网络课堂部分转网页计算部分转编程演练

 制作有趣的网页

首页 > 网络课堂 > 制作有趣的网页 > canvas中绘制Sierpinski三角形
canvas中绘制Sierpinski三角形
Sierpinski三角形,也称谢尔宾斯基三角形,是一种典型的分形图,在介绍分形概念时经常会拿来展示。所谓分形,是一类有共同特征的几何形状,它可以分为几个部分,而每一个部分都近似地是整体缩小后的形状。像Sierpinski三角形,就是如此:
谢尔宾斯基三角形
Sierpinski三角形,总体上看是一个三角形,而通过连接其三个边的中点的线,可以把此三角形分成四个三角形,然后对处于三个顶点的三角形如此继续分割,这样一直进行下去,就形成这个图案。
如果要使用计算机画出Sierpinski三角形,就要找到一种算法,目前分形图常用的算法是递归或迭代,对Sierpinski三角形来说递归比较简单。知乎上有一个Sierpinski三角形画法的递归程序,但是使用Java写的。Java编程比较严格,也相对复杂,而且展示出图形又需要建立一个专用平台,比较繁琐。其实只要搞清楚其编程思路,也就是其中的逻辑,使用其他编程语言也是同样可以实现的,或者会更简单更容易,比如在每台计算机上都有的浏览器中显示,就要简单很多,不需另外加载一个运行环境。但浏览器,也就是网页中,只能使用JavaScript编程语言,上图就是使用JavaScript语言画出来的。JavaScript,一般也简称JS,因为其文件名后缀就是.js,这里不会详细介绍其语法,只是对这段程序功能进行简单介绍。
function drawTrangle(n,context,x1,x2,x3,y1,y2,y3){
  if(n==0) return;
  context.beginPath();
  context.moveTo(x1,y1);
  context.lineTo(x2, y2);
  context.lineTo(x3, y3);
  context.stroke();
  drawTrangle(n-1,context,x1,(x1+x2)/2,(x1+x3)/2,y1,(y1+y2)/2,(y1+y3)/2);
  drawTrangle(n-1,context,(x1+x2)/2,x2,(x2+x3)/2,(y1+y2)/2,y2,(y2+y3)/2);
  drawTrangle(n-1,context,(x1+x3)/2,(x2+x3)/2,x3,(y1+y3)/2,(y2+y3)/2,y3);
}
这里把绘制Sierpinski三角形做成一个递归函数,所谓递归,就是在函数体内会调用自身这个函数,形成一种嵌套。使用递归是有一定风险的,有可能因递归层次过多而造成栈溢出,在浏览器中常见的就是卡死,使浏览器崩溃,所以函数的第一个参数n就是预先设定了一个递归深度,三角形分割过多肉眼也看不到了,所以没有必要把n选得很大,显示出效果就好。因为是画三角形,要有三个顶点,每个顶点有x和y坐标,所以函数参数中有6个坐标值。还有一个context是JS绘图用的上下文参数,这里使用HTML5中加入的canvas容器来绘制图形,它有标准的用法,在最后的完整代码中会有展示。
在函数体内,每次递归都会把n值减1,所以到了设定的最深一层递归时,n为0,就直接返回,避免出现递归深度过深的问题。而在n不为0的情况下,首先要根据函数参数传递进来的三角形的三个顶点绘制出这个三角形。使用HTML5的canvas来绘制三角形,需要使用画线方法context.lineTo(x,y),但这个方法只有终点坐标值,起点则是从上一个点开始的,画三角形的第一个点要使用context.moveTo(x,y),就是要把画笔移动到这个点,然后开始画折线,到第二个点和第三个点,最后使用context.stroke()才会绘制整个路径,而在整个绘制曲线之前,则需要加上context.beginPath(),开始这个路径的绘制。
绘制完成此递归层次的三角形绘制后,要从这三个顶点算出对应的各边的中点坐标值,并作为下一级绘制的顶点坐标,传入到递归调用的函数参数中。下一级需要绘制三个三角形,所以需要递归调用三次。
浏览器中使用上述JS函数,还需要加入另外一部分代码。
var canvas = document.getElementById('canvas'),
  ctx = canvas.getContext('2d'),
  width=canvas.width,
  height=canvas.height;
window.onload=function() {
  ctx.lineWidth=1;
  ctx.strokeStyle='#66aaaa';
  drawTrangle(10,ctx,width/2,0,width,0,height,height);
};
其中前面两行是canvas绘图中标准的用法,首先使用document.getElementById()获取html代码中canvas的id并赋值给变量canvas,然后使用其getContext('2d')方法获得绘制平面图形的上下文并赋给变量ctx。以后的绘制图形相关命令都是ctx的方法,其还有一些属性,比如lineWidth为画线的宽度,单位是像素;strokeStyle为画线的颜色,使用#加rgb的十六进制代码组成字符串来表示。而canvas设定的宽度和高度则使用canvas的width和height属性来表示,绘图时用来确定绘图区域的的边界,避免越界。使用canvas绘图,需要用到解析几何的一些知识,平面及空间的点、线、面、体都是通过其坐标来表示的,这里绘制的是平面图形,所以有横坐标及纵坐标,一般分别以x和y来表示。而网页canvas坐标左上角为(0,0),而右下角为(canvas.width,canvas.height),这与教科书上的直角坐标略有不同,其x轴正方形向右,但y轴正方向向下。
window.onload表示是在网页体加载时调用其中的代码,前面两行设置了画线的宽度和颜色,然后就是调用前面定义的画三角形的函数,其中递归深度设为10,而第一个三角形的三个顶点分别为最上面一行的中点(canvas.width,0)和左下角(0,height)及右下角(width,height)。
为了让上述JavaScript代码在网页中运行,需要把其加入一个最简网页架构中,完整代码为:
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="gb18030" />
  <title>分形</title>
</head>
<body>
<canvas id="canvas" width="600" height="600"> </canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas'),
  ctx = canvas.getContext('2d'),
  width=canvas.width,
  height=canvas.height;
window.onload=function() {
  ctx.lineWidth=1;
  ctx.strokeStyle='#66aaaa';
  drawTrangle(10,ctx,width/2,0,width,0,height,height);
};
function drawTrangle(n,context,x1,x2,x3,y1,y2,y3){
  if(n==0) return;
  context.beginPath();
  context.moveTo(x1,y1);
  context.lineTo(x2, y2);
  context.lineTo(x3, y3);
  context.stroke();
  drawTrangle(n-1,context,x1,(x1+x2)/2,(x1+x3)/2,y1,(y1+y2)/2,(y1+y3)/2);
  drawTrangle(n-1,context,(x1+x2)/2,x2,(x2+x3)/2,(y1+y2)/2,y2,(y2+y3)/2);
  drawTrangle(n-1,context,(x1+x3)/2,(x2+x3)/2,x3,(y1+y3)/2,(y2+y3)/2,y3);
}
</script>
</body>
</html>
可以简单介绍一下html的架构,<!DOCTYPE html>指明是html5网页格式,其后所有代码必须位于<html>和</html>这两个标记之间,这些就是一个网页的完整部分。网页又分为头部和网页体两部分,头部位于<head>和</head>两个标记之间,用于加入一些网页的设置及说明,这部分一般是不会直接展示在浏览器内容中的,比如代码中设置了使用汉字的gb18030字符集,如果显示内容中有汉字字符就不会造成乱码。网页体部分则位于<body>和</body>两个标记之间,这是网页的主体部分,网页中显示的内容一般都位于其中。而<script>和</script>标记之间则是放置JavaScript代码,这部分其实也是可以放置在头部中的,不过现在一般是放在网页体的最后。
使用JavaScript编写代码,比较容易展示。上述代码没有外部引用,可以直接在浏览器中运行。使用不带内置格式的一种编辑器,比如vscode、notepad++等,加入以上代码,存储为html文件格式,比如sierpinski.html,网页中没有引入外部文件因此可以放置在任意位置,比如桌面上,就会显示为默认浏览器的图标。打开这个html文件,就会在默认浏览器中运行,就能显示出上面的Sierpinski三角形图案,非常简便。注意,不要使用word这种文字处理软件来写这种代码,因为会加入一些格式字符,代码就不能运行了。
Copyright@dwenzhao.cn All Rights Reserved   备案号:粤ICP备15026949号
联系邮箱:dwenzhao@163.com  QQ:1608288659