HTMLのCanvasを利用してアトラクタっぽいやつの描写。
こんな感じになりました。
Canvas部分をクリックすることで再描写されます。
以下、ソースです。
HTMLのソース(index.html)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Canvas sample 02 Attractor.</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link rel="stylesheet" type="text/css" href="style.css"/>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div id="wrapper">
<p>Click to reset.</p>
<p>Source code is <a href = "src.zip">Here.</a></p>
<p>AS3 version: <a href="http://wonderfl.net/c/p9i6">PV3Dその10 3Dでアトラクタっぽいの - wonderfl build flash online</a></p>
<canvas id="myCanvas" width="600" height="400" onclick="reset()"></canvas>
</div>
</body>
</html>
JavaScriptのソース(script.js)
var RADIAN = Math.PI / 180;
var FOCUS = 280;
var CENTER_X = ((600 / 2) | 0);
var CENTER_Y = ((400 / 2) | 0);
var NUM_1 = 600;
var NUM_2 = 15;
var width;
var height;
var context;
var bmpd;
var bmpdArray;
var points;
var atts;
var count;
var theta;
var func;
var a, b, c, d, i, j, p, dd, xx, yy, zz, scale;
window.onload = function()
{
var canvas = document.getElementById('myCanvas');
if (! canvas || ! canvas.getContext ) {return false;}
else
{
width = canvas.width;
height = canvas.height;
context = canvas.getContext('2d');
reset();
}
}
function onFrame()
{
context.fillStyle = "#000000";
context.fillRect(0,0,width, height);
bmpd = context.getImageData(0, 0, width, height);
bmpdArray = bmpd.data;
for(i=0; i < count; i++)
{
p = points[i];
xx = Math.cos(theta * RADIAN) * p.x - Math.sin(theta * RADIAN) * p.z;
zz = Math.sin(theta * RADIAN) * p.x + Math.cos(theta * RADIAN) * p.z;
scale = FOCUS * 1.5 / (FOCUS - zz);
xx = ((xx * scale)|0) + CENTER_X;
yy = ((p.y * scale)|0) * (-1) + CENTER_Y;
// 範囲内なら点を打つ
if (xx >= 0 && yy >= 0 && xx < width && yy < height)
{
j = (yy * width + xx)*4;
bmpdArray[j] = p.cR;
bmpdArray[j + 1] = 255;
bmpdArray[j + 2] = p.cB;
bmpdArray[j + 3] = 255;
}
}
context.putImageData(bmpd,0,0);
theta ++;
}
function reset()
{
points = [];
atts = [];
theta = 0;
if(func){ clearInterval(func);}
// 変数の初期化
a=(Math.random() - 0.5) * 4;
if (Math.abs(a) < 1) {a*=2;}
b=(Math.random() - 0.5) * 4;
if (Math.abs(b) < 1){ b*=2;}
c=(Math.random() - 0.5) * 4;
if (Math.abs(c) < 1){ c*=2;}
d=(Math.random() - 0.5) * 4;
if (Math.abs(d) < 1){ d*=2;}
for(i=0; i < NUM_1; i++){atts[i] = new AttrPoint();}
count = 0;
for(j=0 ; j<NUM_2 ; j++)
{
for(i=0; i < NUM_1; i++)
{
dd = atts[i];
dd.x1=Math.sin(a * dd.y0) - dd.z0 * Math.cos(b * dd.x0);
dd.y1=dd.z0 * Math.sin(c * dd.x0) - Math.cos(d * dd.y0);
dd.z1=Math.sin(dd.x0);
points[count] =new Point3D(dd.x1 * 70, dd.y1 * 70 + 20, dd.z1 * 70);
dd.x0=dd.x1;
dd.y0=dd.y1;
dd.z0=dd.z1;
count ++;
}
}
// レンダリング開始
func = setInterval("onFrame()", 30);
}
function AttrPoint()
{
this.x0 = Math.random() * 2.0 - 1.0;
this.y0 = Math.random() * 2.0 - 1.0;
this.z0 = Math.random() * 2.0 - 1.0;
this.x1=0;
this.x2=0;
this.x3=0;
}
function Point3D(x,y,z)
{
this.x = x;
this.y = y;
this.z = z;
this.cR = 255*Math.random();
this.cB = 255*Math.random();
}
CSSのソース(style.css)
*{
margin:0;
padding:0;
border: none;
text-decoration:none;
list-style:none;
font-size:100%;
font-style:normal;
font-weight:normal;
}
a:link
{
text-decoration:underline;
color: #289000;
}
a:visited
{
text-decoration:underline;
color: #599000;
}
a:hover
{
text-decoration:underline;
color: #982000;
}
a:active
{
text-decoration:underline;
color: #599000;
}
body {
text-align:left;
background-color:#ffffff;
}
#wrapper {
font-size:14px;
color: #555555;
width: 600px;
height:500px;
margin-top:100px;
margin-left : auto;
margin-right : auto ;
}
#myCanvas {
margin-top:5px;
background-color: #DDDDDD;
border: 1px solid #777777;
}
