ギアにペンを差し込んでグルグルまわるやつ
'''
'''
<!DOCTYPE html> <meta charset="UTF-8"> <title>HTML canvas </title> <style> ol li label { display: inline-block; width: 10em; padding: 0 1ex; } ol li { margin: 2px; list-style: none; } ol li label, ol li input { border: 2px silver ridge; border-radius: 5px; } </style> <body> <form id="STATE"> <ol> <li> <label>Aria</label> <input type="number" value="1200" step="50" min="50" max="10000"> <li> <label>B:radius</label> <input type="number" value="352" min="0" max="5000"> <li> <label>B:offset</label> <input type="number" value="0.52" min="0.01" max="1" step=".01"> <li> <label>Line color</label> <select> <option value="rgba(0,0,0,.3)">Gray</option> <option value="rgba(255,0,0,.2)">Red</option> <option value="rgba(0,128,0,.2)">Green</option> <option value="rgba(0,0,255,.2)">Blue</option> <option value="rgba(128,0,255,.2)" selected>Violet</option> </select> <li> <label>Line speed</label> <select> <option value="1">Slow</option> <option value="5">Normal</option> <option value="25" selected>Early</option> <option value="100">High speed</option> </select> </li> <li>-------- Option --------- </li> <li> <label>C:radius</label> <input type="number" value="1" min="1" max="20"> <li> <label>C:offset</label> <input type="number" value="0" min="0" max="1" step=".03" max="1"> </ol> </form> <canvas width="1200" height="1200"></canvas> <script> //----------------------------------------------- class Canvas { constructor (e, area, color = 'rgba(0,0,0,.5)') { this.canvas = e; this.ctx = e.getContext ('2d'); this.color = color; this.area = area; this.m = null; } cls () { let { ctx, canvas } = this; ctx.clearRect (0, 0, canvas.width, canvas.height); return this; } set area (p) { if (p) { let { ctx, canvas } = this; [canvas.width, canvas.height] = p.value; this.m = null; ctx.translate (canvas.offsetWidth / 2, canvas.offsetHeight / 2); } } set color (rgba) { this.ctx.strokeStyle = rgba; } line (p) { let {ctx, m} = this; if (null === m) { ctx.moveTo (...p.value); } else { ctx.beginPath (); ctx.moveTo (...m.value); ctx.lineTo (...p.value); ctx.stroke (); } this.m = p; return this; } } //----------------------------------------------- class P { #p = [ ]; constructor (a) { this.#p = a; } add (q) { return new this.constructor (q.value.map ((a,i)=> this.#p[i]+a)) } sub (q) { return new this.constructor (q.value.map ((a,i)=> this.#p[i]-a)) } get value () { return this.#p } set value (p) { this.#p = p } } //----------------------------------------------- class Circle { #rad = null; //ラジアン #c = null; //円周 constructor (radius = 1, offset = 1/* (%) */, rad = 0) { this.radius = radius; this.offset = offset; this.#rad = rad; this.#c = 2 * Math.PI * radius; } rotation (n) { this.#rad += n / this.#c; return this.position; } get position () { let r = this.radius * this.offset; let rad = this.#rad; return new P ([Math.sin (rad) * r, Math.cos (rad) * r]); } } //----------------------------------------------- let CG = new Canvas (document.querySelector ('canvas')), C0 = null, C1 = null, C2 = null, ANIME_ID = null, PM = [...document.querySelectorAll ('form input[type="number"], form select')], STEP = 25, SPEED = null; function draw () { for (let i = SPEED; i--; ) CG.line (C0.rotation (STEP).add (C1.rotation (-STEP)).add(C2.rotation(-STEP))); requestAnimationFrame (draw); } //----------------------------------------------- function demo () { if (ANIME_ID) cancelAnimationFrame (ANIME_ID); let [a, r, offset, col, sp, gr, go] = PM.map (e=> 'valueAsNumber' in e ? e.valueAsNumber: e.value); let r0 = a/2*.95 - ( r * offset); CG.area = new P ([a, a]); CG.color = col; SPEED = +sp; C0 = new Circle (r0, 1), C1 = new Circle (r, offset); C2 = new Circle (gr, go); draw (); } //----------------------------------------------- function hndler () { demo (); } STATE.addEventListener ('change', hndler, false); demo (); </script>