自從上一次繪制雪花曲線(
用javascript繪制雪花(Koch曲線))之后,對簡單分形更加喜歡,太復雜的只能欣賞了,簡單分形還是決定一個一個的用代碼繪制出來,html5中的canvas標簽相當方便,本文繼續使用javascript + canvas的模式。
謝爾賓斯基三角形由波蘭數學家謝爾賓斯基在1915年提出。詳情見
wiki。
總體上說來這個三角形比雪花曲線要來的簡單,基本思路和雪花曲線類似,所以沒有什么難度。

圖1
圖1為謝爾賓斯基三角形的變化規律,由於都是正三角形,所以幾個點處理起來很方便。

圖2
圖2中我們約定了正三角形的三個點分別為P1、P2、P3,中心點的三個點為P4、P5、P6。我們約定:在方法調用的時候P2和P3在一條直線,X3大於X2。這樣約定在遞歸方法中會比較容易處理。
首先是body代碼,加入canvas標簽。並加入適當樣式。
<style
>
canvas{border : 2px solid #000; background :#fff;}
< /style >
<body onload = "draw()" >
<input type = "text" value = "1" id = "txtDepth" / >
<input type = "button" value = "繪制" onclick = "draw()" / >
<input type = "checkbox" id = "cbox" >彩色
<br / >
<canvas id = "cantest" width = "500px" height = "500px" > < /canvas >
< /body >
canvas{border : 2px solid #000; background :#fff;}
< /style >
<body onload = "draw()" >
<input type = "text" value = "1" id = "txtDepth" / >
<input type = "button" value = "繪制" onclick = "draw()" / >
<input type = "checkbox" id = "cbox" >彩色
<br / >
<canvas id = "cantest" width = "500px" height = "500px" > < /canvas >
< /body >
主要代碼:
<script language
=
"javascript"
>
function draw(){
var can = document.getElementById( "cantest");
if(can.getContext){
can.height = can.height;
var ctx = can.getContext( "2d");
ctx.strokeStyle = "#000";
var depth = parseInt(document.getElementById( "txtDepth").value); //繪制維度
Sierpinski(ctx, 250.00, 20.00, 0.00, 500 * Math.sin(Math.PI / 3) + 20, 500.00, 500 * Math.sin(Math.PI / 3) + 20, depth , 0);
} else{
alert( "不支持Canvas");
}
}
if(depth == 0){
return false;
}
if(depth == nowDepth){
ctx.beginPath();
if(document.getElementById( "cbox").checked){
ctx.fillStyle = getColor();
} else{
ctx.fillStyle = "#000";
}
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.fill(); //填充塊
return false;
}
var x4 = x2 + (x3 - x2) / 2;
var x5 = x2 + (x3 - x2) / 4;
var x6 = x2 + (x3 - x2) * 3 / 4;
var y4 = 0.00;
var y5 = 0.00;
var y6 = 0.00;
y4 = y1 + (x3 - x2) * Math.sin(Math.PI / 3);
y5 = y1 + (x3 - x2) / 2 * Math.sin(Math.PI / 3);
y6 = y1 + (x3 - x2) / 2 * Math.sin(Math.PI / 3);
Sierpinski(ctx, x1, y1, x5, y5, x6, y6, depth, nowDepth);
Sierpinski(ctx, x5, y5, x2, y2, x4, y4, depth, nowDepth);
Sierpinski(ctx, x6, y6, x4, y4, x3, y3, depth, nowDepth);
}
function getColor(){
return '#' +(Math.random() *0xffffff << 0).toString( 16);
}
< /script >
function draw(){
var can = document.getElementById( "cantest");
if(can.getContext){
can.height = can.height;
var ctx = can.getContext( "2d");
ctx.strokeStyle = "#000";
var depth = parseInt(document.getElementById( "txtDepth").value); //繪制維度
Sierpinski(ctx, 250.00, 20.00, 0.00, 500 * Math.sin(Math.PI / 3) + 20, 500.00, 500 * Math.sin(Math.PI / 3) + 20, depth , 0);
} else{
alert( "不支持Canvas");
}
}
function Sierpinski(ctx, x1, y1,
x2, y2,
x3, y3,
depth, //維度
nowDepth){ //當前維度
nowDepth
= nowDepth
+
1;
if(depth == 0){
return false;
}
if(depth == nowDepth){
ctx.beginPath();
if(document.getElementById( "cbox").checked){
ctx.fillStyle = getColor();
} else{
ctx.fillStyle = "#000";
}
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.fill(); //填充塊
return false;
}
var x4 = x2 + (x3 - x2) / 2;
var x5 = x2 + (x3 - x2) / 4;
var x6 = x2 + (x3 - x2) * 3 / 4;
var y4 = 0.00;
var y5 = 0.00;
var y6 = 0.00;
y4 = y1 + (x3 - x2) * Math.sin(Math.PI / 3);
y5 = y1 + (x3 - x2) / 2 * Math.sin(Math.PI / 3);
y6 = y1 + (x3 - x2) / 2 * Math.sin(Math.PI / 3);
Sierpinski(ctx, x1, y1, x5, y5, x6, y6, depth, nowDepth);
Sierpinski(ctx, x5, y5, x2, y2, x4, y4, depth, nowDepth);
Sierpinski(ctx, x6, y6, x4, y4, x3, y3, depth, nowDepth);
}
function getColor(){
return '#' +(Math.random() *0xffffff << 0).toString( 16);
}
< /script >
運行后效果如下:

圖3 黑白

圖4 彩色
這次其實用畫線的方法也是可以得,只是上次用過了,下次看到好玩的分形,繼續玩一玩,canvas標簽功能着實強大,應該好好發掘。