xxxxxxxxxx
252
let size = 250;
let radius = 0.85 * size;
let win_w = 0.67 * radius;
let win_h = 0.25 * radius;
let win_top = [size - win_w, size - win_h - 0.3 * radius];
let win_bottom = [size - win_w, size - win_h + 0.3 * radius];
let zoom = 1;
let beta;
let gamma = 0;
let theta = 0;
let drag_start;
let heading_start;
let source;
let dest;
function range(a, b, p) {
let ma = (1 + a / TWO_PI) % 1;
let mb = (1 + b / TWO_PI) % 1;
let na = floor(10 ** (ma + p));
let nb = floor(10 ** (mb + p));
return [na, nb];
}
function ticks(na, nb, r, p, g, inward) {
let n_min = 10 ** p;
let n_max = 10 * n_min - 1;
let m = na;
let n = nb + 1;
while(true) {
let len = 3;
let q = m % 10;
if(q == 5) len = 5;
else if(q == 0) len = 10;
let ang = TWO_PI * (Math.log10(m) - p);
let xu = cos(ang);
let yu = sin(ang);
let xa = r * xu;
let ya = r * yu;
let s = r + len * (inward ? -1 : 1);
let xb = s * xu;
let yb = s * yu;
let m_str = m.toString();
let lbl = m_str[0] + '.' + m_str.slice(1);
g.stroke(0);
g.noFill();
g.line(xa, ya, xb, yb);
if(q == 0 || q == 5 || lbl < 2) {
s = r + 20 * (inward ? -1 : 1);
g.push();
g.translate(s*xu, s*yu);
g.rotate(ang + HALF_PI);
g.noStroke();
g.fill(0);
g.text(lbl, 0, 0);
g.pop();
}
m += 1;
if(m == n) break;
if(m > n_max) m = n_min;
}
}
function draw_zoom_top(r, p) {
source.reset();
source.background('whitesmoke');
source.translate(win_w, win_h + r);
source.rotate(-HALF_PI);
source.stroke('gray');
source.noFill();
source.arc(0, 0, 2*r, 2*r, -beta, beta);
let [na, nb] = range(-beta, beta, p);
ticks(na, nb, r, p, source, false);
source.rotate(gamma);
[na, nb] = range(-gamma-beta, -gamma+beta, p);
ticks(na, nb, r, p, source, true);
image(source, win_top);
}
function draw_zoom_bottom(r, p) {
dest.reset();
dest.background('whitesmoke');
dest.translate(win_w, win_h - r);
dest.rotate(HALF_PI - theta);
dest.stroke('gray');
dest.noFill();
let a = theta - beta;
let b = theta + beta;
dest.arc(0, 0, 2*r, 2*r, a, b);
let [na, nb] = range(a, b, p);
ticks(na, nb, r, p, dest, false);
dest.rotate(gamma);
[na, nb] = range(a - gamma, b - gamma, p);
ticks(na, nb, r, p, dest, true);
image(dest, win_bottom);
}
function draw_zoom() {
let r = zoom * radius;
let p = floor(Math.log10(zoom)) + 1;
beta = asin(win_w / r);
draw_zoom_top(r, p);
draw_zoom_bottom(r, p);
}
function mouseWheel(e) {
let amount = 1 + e.delta / size;
zoom = zoom * amount;
if(zoom < 1) zoom = 1;
else if(zoom > 20000) zoom = 20000;
draw();
return false;
}
function mousePressed() {
drag_start = createVector(mouseX - size, mouseY - size);
if(mouseInTopWin()) {
heading_start = gamma;
} else if(mouseInBottomWin()) {
heading_start = theta;
} else {
heading_start = drag_start.heading() - HALF_PI - gamma;
}
}
let mouseInTopWin = function() {
let left = win_top[0];
let top = win_top[1];
let right = left + 2 * win_w;
let bottom = top + 2 * win_h;
return function() {
return(mouseX > left && mouseY > top &&
mouseX < right && mouseY < bottom);
};
}();
let mouseInBottomWin = function() {
let left = win_bottom[0];
let top = win_bottom[1];
let right = left + 2 * win_w;
let bottom = top + 2 * win_h;
return function() {
return(mouseX > left && mouseY > top &&
mouseX < right && mouseY < bottom);
};
}();
function mouseInMagnifier() {
let v = p5.Vector.fromAngle(theta - HALF_PI, radius)
.add(size - mouseX, size - mouseY);
return v.magSq() < 400;
}
function mouseDragged() {
if(mouseInMagnifier()) {
theta = createVector(mouseX - size, mouseY - size)
.heading() + HALF_PI;
} else if(mouseInTopWin()) {
let phi = beta * (mouseX - size - drag_start.x) / win_w;
gamma = heading_start + phi;
} else if(mouseInBottomWin()) {
let phi = beta * (mouseX - size - drag_start.x) / win_w;
theta = heading_start + phi;
} else {
let heading_end = createVector(mouseX - size, mouseY - size)
.heading() - HALF_PI;
gamma = heading_end - heading_start;
}
draw();
}
function setup() {
createCanvas(2*size, 2*size) .parent('rule');
source = createGraphics(2*win_w, 2*win_h);
dest = createGraphics(2*win_w, 2*win_h);
textAlign(CENTER, CENTER);
textSize(12);
source.textAlign(CENTER, CENTER).textSize(10);
dest.textAlign(CENTER, CENTER).textSize(10);
noLoop();
}
function draw() {
background('white');
let dx = size + radius * cos(theta - HALF_PI);
let dy = size + radius * sin(theta - HALF_PI);
fill(0, 10);
strokeWeight(2);
circle(dx, dy, 40);
strokeWeight(4);
line(dx+15, dy+15, dx+30, dy+30);
noFill();
stroke('gray');
strokeWeight(1);
circle(size, size, 2*radius);
push();
translate(size, size);
rotate(-HALF_PI);
ticks(10, 99, radius, 1, window, false);
rotate(gamma);
ticks(10, 99, radius, 1, window, true);
pop();
draw_zoom();
}
function getVal(id) {
let val = document.getElementById(id).value;
if(!isNaN(val)) {
val = abs(Number(val));
if(val == 0) return 1.0;
while(val >= 10) val /= 10;
while(val < 1) val *= 10;
return val;
}
return 1.0;
}
function assign() {
let op = document.getElementsByName("oper");
let a = getVal("val_a");
let b = getVal("val_b");
gamma = TWO_PI * (1 - Math.log10(a));
theta = TWO_PI * Math.log10(b);
if(op[1].checked) {
gamma = (gamma + theta) % TWO_PI;
} else if(op[2].checked) {
theta = TWO_PI * Math.log10(a);
}
draw();
}