<!DOCTYPE html>
<html>
<head>
<title>Бабочку Хофштадтера</title>
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div class="main">
<canvas id="theCanvas" height="500" width="500"></canvas>
<div id="rightBar">
<h1>Бабочку Хофштадтера</h1>
<form>
<div class="Buttons">
<button id="startButton" onclick="start();" type="button">Старт</button>
<button id="stopButton" onclick="stop();" type="button">Стоп</button>
</div>
<div class="values">
<label for="qValue">
<p>q:</p>
</label>
<span id="qValue">0</span>
</div>
</form>
</div>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
}
body {
max-width: 100%;
background-color: #d4d4d4;
}
.main {
width: 58vw;
display: flex;
margin: 1vw auto;
border: 5px solid black;
}
canvas {
margin: ;
/* border: 2px solid red;*/
}
#rightBar {
width: 20vw;
background-color: #a6c5ff;
/* border: 1px solid blue;*/
}
h1 {
font-size: 1.5vw;
text-align: center;
}
.Buttons {
width: 15vw;
display: flex;
margin: 1vw auto;
text-align: center;
}
#startButton {
margin-right: 3vw;
border: 0 solid red;
width: 6vw;
display: flex;
color: #fff;
text-decoration: none;
text-transform: uppercase;
font-size: 1vw;
background: #6530ff;
padding: 0.2vw 0.1vw 0.1vw 1.4vw;
transition: .3s cubic-bezier(0.2, 0, 1, 1);
}
#startButton:hover {
background: #B69EFC;
padding: 0.2vw 0.1vw 0.1vw 1.4vw;
border-radius: 1vw;
font-size: 1vw;
}
#stopButton {
border: 0 solid red;
width: 6vw;
display: flex;
color: #fff;
text-decoration: none;
text-transform: uppercase;
font-size: 1vw;
background: #6530ff;
padding: 0.2vw 0.1vw 0.1vw 1.6vw;
transition: .3s cubic-bezier(0.2, 0, 1, 1);
}
#stopButton:hover {
background: #B69EFC;
padding: 0.2vw 0.1vw 0.1vw 1.6vw;
border-radius: 1vw;
font-size: 1vw;
}
.values {
display: flex;
font-size: 1.5vw;
width: 3vw;
margin: 0 auto;
}
var keepRunning = true;
var canvas, ctx, w, h;
var q = 4,
qmax = 280;
var MAXX, MAXY;
// flip x, y
function drawPoint(x, y) {
// console.log('drawPoint(', x, y, ')');
ctx.beginPath();
ctx.fillRect(y, x, 1, 1);
ctx.stroke();
}
function next() {
$('#qValue').text(q);
// puffer=createImage(getSize().width,getSize().height);
// puffer=createImage(600,500);
// pufferG=puffer.getGraphics();
// Increase qmax for greater detail, at the expense of more time.
var p, i, j, ie, n, nalt = 0,
m, neu;
var sigma, e, polyalt, poly, polyneu;
var doubleCosSigma, doubleCosSigmaQ_2, invQ = 1.0 / q;
ctx.strokeStyle = 'black';
ctx.fillStyle = 'black';
// pufferG.setColor(Color.black);
// for q=2 the points (eigenvalues) are explicitly drawn
for (p = 1; p < q; p += 2) {
if (gcd(p, q) > 1) continue;
sigma = 2.0 * Math.PI * p * invQ;
// optimize by caching 1/q, cos(sigma), etc.
// Is there a trig identity that will help us optimize cos(sigma * m)?
// I don't think so, except where m=2.
doubleCosSigma = 2.0 * Math.cos(sigma);
doubleCosSigmaQ_2 = 2.0 * Math.cos(sigma * q * 0.5);
nalt = 0;
for (ie = 0; ie < MAXY + 2; ie++) {
e = 8.0 * ie / MAXY - 4.0 - 4.0 / MAXY;
n = 0;
/* odd wavefunctions */
polyalt = 1.0;
poly = doubleCosSigma - e;
if (polyalt * poly < 0.0) n++;
for (m = 2; m < q / 2; m++) {
polyneu = (2.0 * Math.cos(sigma * m) - e) * poly - polyalt;
if (poly * polyneu < 0.0) n++;
polyalt = poly;
poly = polyneu;
}
polyalt = 1.0;
poly = 2.0 - e;
if (polyalt * poly < 0.0) n++;
polyneu = (doubleCosSigma - e) * poly - 2.0 * polyalt;
if (poly * polyneu < 0.0) n++;
polyalt = poly;
poly = polyneu;
for (m = 2; m < q / 2; m++) {
polyneu = (2.0 * Math.cos(sigma * m) - e) * poly - polyalt;
if (poly * polyneu < 0.0) n++;
polyalt = poly;
poly = polyneu;
}
polyneu = (doubleCosSigmaQ_2 - e) * poly - 2.0 * polyalt;
if (poly * polyneu < 0.0) n++;
/* even wavefunctions */
polyalt = 1.0;
poly = 2.0 - e;
if (polyalt * poly < 0.0) n++;
polyneu = (doubleCosSigma - e) * poly - 2.0 * polyalt;
if (poly * polyneu < 0.0) n++;
polyalt = poly;
poly = polyneu;
for (m = 2; m < q / 2; m++) {
polyneu = (2.0 * Math.cos(sigma * m) - e) * poly - polyalt;
if (poly * polyneu < 0.0) n++;
polyalt = poly;
poly = polyneu;
}
polyneu = (doubleCosSigmaQ_2 - e) * poly - 2.0 * polyalt;
if (poly * polyneu < 0.0) n++;
if (n > nalt) {
// if(neu==1) {g.drawImage(puffer,0,0,this);neu=0;}
drawPoint(MAXX * p * invQ, MAXY - ie);
// pufferG.drawLine(MAXX*p/q,MAXY-ie,MAXX*p/q,MAXY-ie);
}
nalt = n;
}
}
// TODO: drawString("q= " + q);
q += 2;
if (keepRunning && q <= qmax) {
// stop and give UI a chance to catch up, between iterations of q
window.setTimeout(next, 1);
}
}
function start() {
canvas = document.getElementById('theCanvas');
ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
w = canvas.scrollWidth;
h = canvas.scrollHeight;
MAXX = w;
MAXY = h;
drawPoint(MAXX / 2, MAXY * (1 - (4 + Math.sqrt(8)) / 8));
drawPoint(MAXX / 2, MAXY * (1 - (4 - Math.sqrt(8)) / 8));
q = 4;
keepRunning = true;
window.setTimeout(next, 2);
}
function stop() {
keepRunning = false;
}
function gcd(a, b) {
if (b == 0) return a;
return gcd(b, a % b);
}