123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- 'use strict';
- /* global variables */
- var STRETCH_X = 3;
- var STRETCH_Y = 0.5;
- var X_MIN = -10;
- var X_MAX = +10;
- var Y_MIN = -10;
- var Y_MAX = +10;
- var X_OFFSET = -128;
- var Y_OFFSET = 256;
- var INITIAL_RADIUS = 20;
- var POINT_RADIUS = 5;
- /*******************************************************************/
- /* Graphics */
- /*******************************************************************/
- /**
- * Calculates coordinates from worldspace to screenspace
- * @param {Number} x the coordinate you want to transform
- * @param {bool} isX true iff x is a x-coordinate, otherwise false
- * @return {Number} transformed coordinate
- */
- function c(x, isX) {
- if (isX) {
- return STRETCH_X * (x - X_OFFSET);
- }
- return STRETCH_Y * (-x + Y_OFFSET);
- }
- /**
- * Calculates coordinates from screenspace to worldspace
- * @param {Number} x the coordinate you want to transform
- * @param {bool} isX true iff x is a x-coordinate, otherwise false
- * @return {Number} transformed coordinate
- */
- function r(x, isX) {
- if (isX) {
- return (x / STRETCH_X) + X_OFFSET;
- }
- return (-x / STRETCH_Y) + Y_OFFSET;
- }
- function setCursorByID(id,cursorStyle) {
- var elem;
- if (document.getElementById &&
- (elem=document.getElementById(id)) ) {
- if (elem.style) elem.style.cursor=cursorStyle;
- }
- }
- function drawEllipse(centerX, centerY, width, height) {
- context.beginPath() ;
- var x = centerX;
- var y = centerY;
- var rx = width;
- var ry = height;
- var rotation = 0; // The rotation of the ellipse (in radians)
- var start = 0; // The start angle (in radians)
- var end = 2 * Math.PI; // The end angle (in radians)
- var anticlockwise = false;
- context.ellipse(x, y, rx, ry, rotation, start, end, anticlockwise);
- context.fillStyle = "rgba(255, 0, 0, 0.5)";
- context.fill();
- }
- function getColor(i, transparency) {
- //var t = (i+1)*(360/k);
- //var color = 'hsla('+t+', 100%, 50%, '+transparency+')';
- var x = i / 256;
- if (x > 1) {x = 1.0;}
- x = parseInt(x*255);
- var color = 'rgba('+x+','+x+','+x+','+transparency+')';
- return color;
- }
- function drawFunction(canvas) {
- var add = parseInt(document.getElementById("density").value);
- context.beginPath();
- context.fillStyle = 'red';
- context.moveTo(0, c(getValue(r(0))), false);
- for (var xS=0; xS < canvas.width; xS+=add) {
- var x = r(xS);
- var y = getValue(x);
- context.lineTo(c(x, true), c(y, false));
- }
- context.closePath();
- context.stroke();
- }
- /*******************************************************************/
- /* Math */
- /*******************************************************************/
- function euklideanDist(p1, p2) {
- return Math.sqrt(
- Math.pow(p1["x"]-p2["x"], 2)
- + Math.pow(p1["y"]-p2["y"], 2));
- }
- /**
- * Calculates the value of a cubic function at x
- * @param {Number} x
- * @return {Number} f(x)
- */
- function getValue(x) {
- var a = parseFloat(document.getElementById("a").value);
- var b = parseFloat(document.getElementById("b").value);
- var c1 = parseFloat(document.getElementById("c").value);
- return a*x*x+b*x+c1;
- }
- /**
- * Calculates the drivate f'(x)
- * @param {Number} x
- * @return {Number} f'(x)
- */
- function getDValue(x) {
- var a = parseFloat(document.getElementById("a").value);
- var b = parseFloat(document.getElementById("b").value);
- return 2*a*x+b;
- }
- /**
- * Calculates the drivate f''(x)
- * @param {Number} x
- * @return {Number} f''(x)
- */
- function getDDValue(x) {
- var a = parseFloat(document.getElementById("a").value);
- return 2*a;
- }
- /**
- * Calculates (f(x)^2)' = ((a*x*x+b*x+c)^2)' = 2 (b + 2 a x) (c + x (b + a x))
- * @param {Number} x
- * @return {Number} (f(x)^2)'
- */
- function gedSquaredValueD(x) {
- var a = parseFloat(document.getElementById("a").value);
- var b = parseFloat(document.getElementById("b").value);
- var c1 = parseFloat(document.getElementById("c").value);
- return 2*(2*a*x+b)*(x*(a*x+b)+c1);
- }
- /**
- * Calculates (f(x)^2)'' = ((a*x*x+b*x+c)^2)'' = 2 (b^2 + 6 a b x + 2 a (c + 3 a x^2))
- * @param {Number} x
- * @return {Number} (f(x)^2)''
- */
- function gedSquaredValueDD(x) {
- var a = parseFloat(document.getElementById("a").value);
- var b = parseFloat(document.getElementById("b").value);
- var c1 = parseFloat(document.getElementById("c").value);
- return 2*(b*b+6*a*b*x+2*a*(c1+3*a*x*x));
- }
- function findMin(p) {
- var a = parseFloat(document.getElementById("a").value);
- var b = parseFloat(document.getElementById("b").value);
- var c1 = parseFloat(document.getElementById("c").value);
- /* old iterative solution that had problems near the center*/
- var lastx = -10000;
- var x = p.x;
- var i = 0;
- while (Math.abs(lastx-x) > 1 && i < 100) {
- // first derivate of the square of the distance function
- var fx = -2.0*p.x+2.0*x-2.0*p.y*getDValue(x) +2*getValue(x)*getDValue(x);
- var fxd = 2.0 -2.0*p.y*getDDValue(x)+2*(getDValue(x)*getDValue(x) + getValue(x)*getDDValue(x));
- if (fxd == 0) {
- console.log("wow!");
- return x;
- }
- // x_{n+1} = x_n - f(x_n)/f'(x_n) wenn x gesucht, sodass f(x) = 0 gilt
- lastx = x;
- x -= fx / fxd;
- i++;
- }
- // New direct solution
- /*var xs = -b / (2*a);
- var w = p.y + b*b/(4*a)-c1;
- var z = p.x + b / (2*a);
- var alpha = (1-2*a*w)/(2*a*a);
- var beta = -z/(2*a*a);
- var t = Math.pow(Math.pow(3*(4*Math.pow(alpha,3) +27* Math.pow(beta,2)),1/2) - 9*beta, 1/3);
- var currentMinX = t / (Math.pow(18, 1/3)) - Math.pow(2/3*alpha, 1/3) / t;
- */
-
- return x;
- }
- function getDist(p, minX) {
- var minY = getValue(minX);
- return euklideanDist({"x":minX, "y":minY}, {"x":p.x, "y":p.y});
- }
- /*******************************************************************/
- /* Start / Update */
- /*******************************************************************/
- function drawBoard(canvas, mouseCoords, radius) {
- var context = canvas.getContext('2d');
- context.canvas.width = window.innerWidth - 50;
- context.canvas.height = window.innerHeight - 120;
- context.clearRect(0, 0, canvas.width, canvas.height);
- drawFunction(canvas);
- if (document.getElementById("pDistance").checked) {
- var add = parseInt(document.getElementById("density").value)+10;
- for (var x=0; x < canvas.width; x+=add) {
- for (var y=0; y < canvas.height; y+=add) {
- var dist = getDist({"x":r(x,true), "y":r(y,false)}, findMin({"x":r(x,true), "y":r(y,false)}));
- context.fillStyle = getColor(dist,0.5);
- context.fillRect(x, y, add/2, add/2);
- }
- }
- }
- }
- function updateBoard(){
- var canvas = document.getElementById("myCanvas");
- STRETCH_X = parseFloat(document.getElementById("STRETCH_X").value);
- STRETCH_Y = parseFloat(document.getElementById("STRETCH_Y").value);
- X_OFFSET = parseFloat(document.getElementById("X_OFFSET").value);
- Y_OFFSET = parseFloat(document.getElementById("Y_OFFSET").value);
- drawBoard(canvas, {"x":0,"y":0}, INITIAL_RADIUS);
- }
- var canvas = document.getElementById("myCanvas");
- var context = canvas.getContext("2d");
- drawBoard(canvas, {"x":0,"y":0}, INITIAL_RADIUS);
- setCursorByID("myCanvas", "crosshair");
- /** get the current position of the mouse */
- function getMouseCoords(canvas, evt) {
- var rect = canvas.getBoundingClientRect();
- return {
- "x": evt.clientX - rect.left,
- "y": evt.clientY - rect.top
- };
- }
- /** event listeners */
- canvas.addEventListener('mousemove',
- function (evt) {
- var mouseCoords = getMouseCoords(canvas, evt);
- drawBoard(canvas, mouseCoords, 10);
- // draw coordinates next to mouse
- context.fillStyle = "blue";
- context.font = "bold 16px Arial";
- var x = r(mouseCoords.x, true).toFixed(3);
- var y = r(mouseCoords.y, false).toFixed(3);
- context.fillText("(" + x + ", " + y + ")", mouseCoords.x + 5, mouseCoords.y - 5);
- var minX = findMin({"x": r(mouseCoords.x,true), "y": r(mouseCoords.y,false)});
- var minY = getValue(minX);
- context.beginPath();
- context.moveTo(c(minX,true), c(minY, false));
- context.lineTo(mouseCoords.x, mouseCoords.y, false);
- context.stroke();
- var minRadius = euklideanDist({"x": r(mouseCoords.x,true), "y": r(mouseCoords.y,false)}, {"x":minX,"y":minY});
-
- /* Draw circle */
- drawEllipse(mouseCoords.x, mouseCoords.y, minRadius*STRETCH_X, minRadius*STRETCH_Y);
- }, false);
|