kaka.farm

Unnamed repository; edit this file 'description' to name the repository.
git clone https://kaka.farm/~git/kaka.farm
Log | Files | Refs | README

main.js (8830B)


      1 Math.TAU = 2 * Math.PI;
      2 
      3 (function() {
      4 	let turn = 0;
      5 	let last_time = 0;
      6 	let math_ts;
      7 	let math_yss;
      8 	let math_polygon_radiuses;
      9 	let canvas_ts;
     10 	let canvas_yss;
     11 	let canvas_polygon_radiuses;
     12 
     13 	const NUMBER_OF_POLYGONS = 7;
     14 	const POLYGON_HEIGHT_MARGIN = 0.075;
     15 	const TURN_PER_MILLISECOND = 0.0005;
     16 	const CYCLE_LENGTH = 20;
     17 	const NUMBER_OF_SAMPLES = 500;
     18 	const START_T = 0;
     19 	const END_T = CYCLE_LENGTH;
     20 	const math_graph_y_extents = [
     21 		[-1.2, 1.2],
     22 		[-1.2, 1.2],
     23 		[-1.2, 1.2],
     24 		[-1.2, 1.2],
     25 		[-1.2, 1.2],
     26 		[-1.2, 1.2],
     27 		[-1.2, 1.2],
     28 	];
     29 
     30 
     31 
     32 	const functions = [
     33 		/*
     34 		turn => step_on(turn % CYCLE_LENGTH, 1, 1.5) - step_on(turn % CYCLE_LENGTH, 2, 2.5) +
     35 			step_on(turn % CYCLE_LENGTH, 3, 3.5) - step_on(turn % CYCLE_LENGTH, 4, 4.5) +
     36 			step_on(turn % CYCLE_LENGTH, 5, 5.5) - step_on(turn % CYCLE_LENGTH, 6, 6.5) +
     37 
     38 			step_on(turn % CYCLE_LENGTH, 7, 7.5) - step_on(turn % CYCLE_LENGTH, 8.5, 9) +
     39 			step_on(turn % CYCLE_LENGTH, 9.5, 10) - step_on(turn % CYCLE_LENGTH, 11, 11.5) +
     40 			step_on(turn % CYCLE_LENGTH, 12, 12.5) - step_on(turn % CYCLE_LENGTH, 13.5, 14) +
     41 
     42 			step_on(turn % CYCLE_LENGTH, 14.5, 15) - step_on(turn % CYCLE_LENGTH, 15.5, 16) +
     43 			step_on(turn % CYCLE_LENGTH, 16.5, 17) - step_on(turn % CYCLE_LENGTH, 17.5, 18) +
     44 			step_on(turn % CYCLE_LENGTH, 18.5, 19) - step_on(turn % CYCLE_LENGTH, 19.5, 20),
     45 		*/
     46 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 7),
     47 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 6),
     48 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 5),
     49 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 4),
     50 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 3),
     51 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH * 2),
     52 		turn => Math.sin(turn * Math.TAU / CYCLE_LENGTH),
     53 	];
     54 
     55 	function quadratic_stepper(t) {
     56 		if (t < 0) {
     57 			return 0;
     58 		} else if (t < 0.5) {
     59 			return 2 * t**2;
     60 		} else if (t < 1) {
     61 			return (-2*((t-1)**2) + 1);
     62 		} else {
     63 			return 1;
     64 		}
     65 	}
     66 	
     67 	function lerp(t, a, b) {
     68 		return (b - a) * t + a;
     69 	}
     70 
     71 	function superlerp(t, a, b, c, d) {
     72 		// [a, b] ; -a
     73 		// [0, b-a] ; /(b-a)
     74 		// [0, 1] ; *(d-c)
     75 		// [0, d-c] ; +c
     76 		// [c, d]
     77 		return (t - a) / (b - a) * (d - c) + c;
     78 	}
     79 
     80 	function step_on(t, a, b) {
     81 		return quadratic_stepper(superlerp(t, a, b, 0, 1));
     82 	}
     83 
     84 	function step_on_step_off(t, a, b, c, d) {
     85 		return step_on(t, a, b) - step_on(t, c, d);
     86 	}
     87 
     88 	function from_math_coordinates_to_canvas_coordinates(x, y, x_extents, y_extents) {
     89 		let canvas = document.getElementById('canvas');
     90 
     91 		// a, b / - a
     92 		// 0, b-a / * w
     93 		// 0, (b-a)w / /(b-a)
     94 		// 0, w
     95 		
     96 		// a, b / *(-1)
     97 		// -b, -a / +b
     98 		// 0, (b-a) / * h
     99 		// 0, (b-a)h / /(b-a)
    100 		// 0, h
    101 		
    102 		return [
    103 			(x - x_extents[0]) * canvas.width / (x_extents[1] - x_extents[0]),
    104 			((-y) + y_extents[1]) * canvas.height / (y_extents[1] - y_extents[0]),
    105 		];
    106 	}
    107 
    108 	function make_regular_polygon_path2d(x, y, radius, number_of_sides, turn) {
    109 		// `x` and `y` are the center of the triangle.
    110 		// `radius` is the distance from the center to a vertex.
    111 		// `number_of_sides` of the polygon.
    112 		// `turn` is a value [0, 1] where 1 is a full turn.
    113 		
    114 		let regular_polygon = new Path2D();
    115 		
    116 		regular_polygon.moveTo(
    117 			x + Math.cos(turn * Math.TAU) * radius,
    118 			y + Math.sin(turn * Math.TAU) * radius,
    119 		);
    120 
    121 		for (let vertex_i = 1; vertex_i < number_of_sides; vertex_i++) {
    122 			regular_polygon.lineTo(
    123 				x + Math.cos((vertex_i / number_of_sides + turn) * Math.TAU) * radius,
    124 				y + Math.sin((vertex_i / number_of_sides + turn) * Math.TAU) * radius,
    125 			);
    126 		}
    127 
    128 		regular_polygon.closePath();
    129 
    130 		return regular_polygon;
    131 	}
    132 
    133 	function linspace(start, stop, number_of_points) {
    134 		let l = [];
    135 		for (let point_i = 0; point_i < number_of_points; point_i++) {
    136 			l.push(superlerp(point_i, 0, number_of_points - 1, start, stop));
    137 		}
    138 		return l;
    139 	}
    140 
    141 	function draw_polygon(number_of_sides, turn, polygon_center_y, polygon_radius_addition) {
    142 		let canvas = document.getElementById('canvas');
    143 		let ctx = canvas.getContext('2d');
    144 
    145 		ctx.beginPath()
    146 		ctx.fillStyle = '#f0f'; // Fuchia from https://www.w3schools.com/colors/colors_names.asp
    147 		ctx.strokeStyle = '#f0f';
    148 		ctx.fill(
    149 			make_regular_polygon_path2d(
    150 				canvas.width / 2,
    151 				polygon_center_y,
    152 				20 * canvas.height / 500 + polygon_radius_addition,
    153 				number_of_sides,
    154 				turn,
    155 			),
    156 		);
    157 		ctx.stroke(
    158 			make_regular_polygon_path2d(
    159 				canvas.width / 2,
    160 				polygon_center_y,
    161 				20 * canvas.height / 500 + polygon_radius_addition,
    162 				number_of_sides,
    163 				turn,
    164 			),
    165 		);
    166 	}
    167 
    168 	function draw_graph(polygon_i) {
    169 		let canvas = document.getElementById('canvas');
    170 		let ctx = canvas.getContext('2d');
    171 
    172 		ctx.beginPath()
    173 		ctx.strokeStyle = 'white';
    174 		ctx.moveTo(canvas_ts[0], canvas_yss[polygon_i][0]);
    175 		for (let point_i = 1; point_i < NUMBER_OF_SAMPLES; point_i++) {
    176 			ctx.lineTo(canvas_ts[point_i], canvas_yss[polygon_i][point_i]);
    177 		}
    178 		ctx.stroke();
    179 	}
    180 
    181 	function draw_position_circle(x, y) {
    182 		let canvas = document.getElementById('canvas');
    183 		let ctx = canvas.getContext('2d');
    184 
    185 		ctx.beginPath();
    186 		ctx.fillStyle = "#00bfff"; // DeepSkyBlue from https://www.w3schools.com/colors/colors_names.asp
    187 		ctx.arc(x, y, canvas.height / 80, 0, Math.TAU, false);
    188 		ctx.fill();
    189 	}
    190 
    191 	function draw() {
    192 		let canvas = document.getElementById('canvas');
    193 		let ctx = canvas.getContext('2d');
    194 
    195 		ctx.beginPath();
    196 		ctx.fillStyle='black';
    197 		ctx.fillRect(0, 0, canvas.width, canvas.height);
    198 
    199 		ctx.beginPath();
    200 		ctx.strokeStyle = 'white';
    201 
    202 		//ctx.moveTo(START_T, functions[polygon_i](-1) * canvas.width);
    203 
    204 		ctx.lineWidth = 2;
    205 
    206 		// [50, h - 50]
    207 		// 0, 1, 2 / /n-1
    208 		// 0, 0.5, 1 / *(h-h0.1)
    209 		// 0, 0.5(0.9h), 0.9h / +h0.05
    210 		// 50, 0.5(h-100)+0.05h, 0.9h+0.05h
    211 		for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) {
    212 			// top and bottom of the are dedicated to this graph.
    213 			let y_top = polygon_i * canvas.height / NUMBER_OF_POLYGONS;
    214 			let y_bottom = (polygon_i + 1) * canvas.height / NUMBER_OF_POLYGONS;
    215 
    216 			// the vertical value of the center of the current polygon.
    217 			let polygon_y = superlerp(
    218 				polygon_i,
    219 				0,
    220 				NUMBER_OF_POLYGONS - 1,
    221 				POLYGON_HEIGHT_MARGIN * canvas.height,
    222 				canvas.height * (1 - POLYGON_HEIGHT_MARGIN),
    223 			);
    224 
    225 			// Get all cached values of the mathematical and graphical
    226 			let current_sample_i = Math.floor(turn / CYCLE_LENGTH * canvas_ts.length) % canvas_ts.length;
    227 			let current_math_t = math_ts[current_sample_i]; //superlerp(current_math_t, START_T, END_T, 0, canvas.width);
    228 			let current_canvas_t = canvas_ts[current_sample_i];
    229 			let current_math_y = math_yss[polygon_i][current_sample_i];
    230 			//let current_math_y = functions[1](current_math_t);
    231 			let current_canvas_y = canvas_yss[polygon_i][current_sample_i]; // superlerp(current_math_y, -1.2, 1.2, y_bottom, y_top);
    232 
    233 			draw_graph(polygon_i);
    234 
    235 			draw_polygon(polygon_i + 3, current_math_y, polygon_y, canvas_polygon_radiuses[polygon_i][current_sample_i]);
    236 
    237 			draw_position_circle(current_canvas_t, current_canvas_y);
    238 		}
    239 	}
    240 
    241 	function step(time_since_start) {
    242 		draw();
    243 
    244 		turn = TURN_PER_MILLISECOND * time_since_start;
    245 
    246 		window.requestAnimationFrame(step);
    247 	}
    248 
    249 	function resize_window() {
    250 		// https://stackoverflow.com/a/32119392
    251 
    252 		let canvas = document.getElementById('canvas');
    253 
    254 		canvas.width = window.innerWidth;
    255 		canvas.style.width = window.innerWidth;
    256 		canvas.height = window.innerHeight;
    257 		canvas.style.height = window.innerHeight;
    258 
    259 		cache_canvas_data();
    260 	}
    261 
    262 	function cache_math_data() {
    263 		math_ts = Float32Array.from(linspace(START_T, END_T, NUMBER_OF_SAMPLES));
    264 		math_yss = [];
    265 		math_polygon_radiuses = [];
    266 		for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) {
    267 			math_yss.push(Float32Array.from(math_ts));
    268 			for (let t_i = 0; t_i < math_ts.length; t_i++) {
    269 				let y = functions[polygon_i](math_ts[t_i]);
    270 				math_yss[polygon_i][t_i] = y;
    271 			}
    272 			math_polygon_radiuses[polygon_i] = math_yss[polygon_i].map(y => (y > 0.7) ? (y - 0.7) : 0);
    273 		}
    274 	}
    275 
    276 	function cache_canvas_data() {
    277 		let canvas = document.getElementById('canvas');
    278 
    279 		canvas_yss = [];
    280 		canvas_polygon_radiuses = [];
    281 		for (let polygon_i = 0; polygon_i < NUMBER_OF_POLYGONS; polygon_i++) {
    282 			let y_top = polygon_i * canvas.height / NUMBER_OF_POLYGONS;
    283 			let y_bottom = (polygon_i + 1) * canvas.height / NUMBER_OF_POLYGONS;
    284 
    285 			canvas_ts = math_ts.map(t => superlerp(t, START_T, END_T, 0, canvas.width));
    286 			canvas_yss[polygon_i] = math_yss[polygon_i].map(
    287 				y => superlerp(
    288 					y,
    289 					math_graph_y_extents[polygon_i][0],
    290 					math_graph_y_extents[polygon_i][1],
    291 					y_bottom, y_top));
    292 			canvas_polygon_radiuses[polygon_i] = math_polygon_radiuses[polygon_i].map(x => x * (canvas.height / 500) * 100)
    293 		}
    294 	}
    295 
    296 	function main() {
    297 		cache_math_data();
    298 		resize_window();
    299 
    300 		window.addEventListener('resize', resize_window)
    301 		window.requestAnimationFrame(step);
    302 	}
    303 
    304 	window.addEventListener('load', main);
    305 })();