main v1.0
Benjamin Kraft 2 years ago
commit dc030f63ad
  1. 2
      .gitignore
  2. 6
      project.json
  3. 87
      public/color_picker_styles.css
  4. 98
      public/index.html
  5. 259
      public/scripts/Editor.js
  6. 59
      public/scripts/Graph.js
  7. 38
      public/scripts/ObjectStore.js
  8. 17
      public/scripts/Variable.js
  9. 357
      public/scripts/lib/BenjoLibrary.js
  10. 319
      public/scripts/sketch.js
  11. 147
      public/styles.css
  12. BIN
      public/thumbnail.png

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea

@ -0,0 +1,6 @@
{
"display_name": "Maths",
"info_text": "My try of copying GeoGebra.",
"visible": false,
"tags": ["Tool", "Maths"]
}

@ -0,0 +1,87 @@
#color_picker{
width: 350px;
height: 320px;
margin: 20px;
border: 5px solid #000;
background-color: #000;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
position: relative;
}
#color_picker_numeric{
width: 80%;
padding: 5%;
margin: 5%;
background-color: #888;
border-radius: 10px;
overflow: auto;
}
.color_picker_rgb{
float: left;
width: 24%;
height: 35px;
font-size: 25px;
color: #000;
}
.color_picker_rgb:nth-child(1){
margin-right: 10%;
margin-left: 4%;
background-color: #F00;
}
.color_picker_rgb:nth-child(2){
background-color: #0F0;
}
.color_picker_rgb:nth-child(3){
margin-left: 10%;
background-color: #00F;
color: #FFF;
}
#color_picker_hex{
width: 50%;
height: 30px;
font-size: 25px;
margin: 10% 25% 0 25%;
}
#saturation{
position: relative;
width: calc(100% - 33px);
height: 100%;
background: linear-gradient(to right, #FFF 0%, #F00 100%);
float: left;
margin-right: 6px;
}
#value {
width: 100%;
height: 100%;
background: linear-gradient(to top, #000 0%, rgba(255,255,255,0) 100%);
}
#sb_picker{
border: 2px solid;
border-color: #FFF;
position: absolute;
width: 14px;
height: 14px;
border-radius: 10px;
bottom: 50px;
left: 50px;
box-sizing: border-box;
z-index: 10;
}
#hue {
width: 27px;
height: 100%;
position: relative;
float: left;
background: linear-gradient(to bottom, #F00 0%, #F0F 17%, #00F 34%, #0FF 50%, #0F0 67%, #FF0 84%, #F00 100%);
}
#hue_picker {
position: absolute;
background: #000;
border-bottom: 1px solid #000;
top: 0;
width: 27px;
height: 2px;
}

@ -0,0 +1,98 @@
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.6.4.min.js" type="text/javascript"></script>
<script src="scripts/lib/BenjoLibrary.js" type="text/javascript"></script>
<script src="scripts/sketch.js" type="text/javascript"></script>
<script src="scripts/Editor.js" type="text/javascript"></script>
<script src="scripts/Graph.js" type="text/javascript"></script>
<script src="scripts/Variable.js" type="text/javascript"></script>
<script src="scripts/ObjectStore.js" type="text/javascript"></script>
<link href="styles.css" rel="stylesheet">
<link href="color_picker_styles.css" rel="stylesheet">
<title>Graph</title>
</head>
<body>
<div id="canvas_holder"></div>
<div id="displayer">
<center>
<fieldset class="holder" id="function_holder">
<legend>Funktionen</legend>
<table cellpadding="3" class="displayer" id="functions">
<!-- Javascript cells -->
</table>
</fieldset>
<fieldset class="holder" id="variable_holder">
<legend>Variablen</legend>
<table cellpadding="3" class="displayer" id="variables">
noch nicht implementiert
<!-- Javascript cells -->
</table>
</fieldset>
<fieldset class="holder" id="settings_holder">
<legend>Einstellungen</legend>
<span>Scroll-Verhalten:</span>
<input id="scroll_input" max="500" min="0" onchange="updateScroll()" type="range">
<span>X-Axen Verschiebung:</span>
<select id="x_axis_dispo" onchange="updateDisposition(this, true)">
<option value="1">1</option>
<option value="PI">PI</option>
</select>
<br>
<br>
<span>Y-Axen Verschiebung:</span>
<select id="y_axis_dispo" onchange="updateDisposition(this, false)">
<option value="1">1</option>
<option value="PI">PI</option>
</select>
</fieldset>
</center>
</div>
<div id="input_holder">
<input id="submit" onclick="addGraph()" type="button" value="OK"/>
<input id="input" type="text"/>
</div>
<div id="graph_editor_wrapper">
<div id="graph_editor">
<div id="color_picker">
<div id="saturation">
<div id="value">
<div id="sb_picker"></div>
</div>
</div>
<div id="hue">
<div id="hue_picker"></div>
</div>
</div>
<div id="color_picker_numeric">
<input class="color_picker_rgb" max="255" min="0" onchange="currentEditor.colorPicker.updateFromRGB()" oninput="currentEditor.colorPicker.updateFromRGB()" type="number"/>
<input class="color_picker_rgb" max="255" min="0" onchange="currentEditor.colorPicker.updateFromRGB()" oninput="currentEditor.colorPicker.updateFromRGB()" type="number"/>
<input class="color_picker_rgb" max="255" min="0" onchange="currentEditor.colorPicker.updateFromRGB()" oninput="currentEditor.colorPicker.updateFromRGB()" type="number"/>
<input id="color_picker_hex" onchange="currentEditor.colorPicker.updateFromHEX(this, false)" style="background-color: #F00;" style="background-color: #F00;" type="text"/>
</div>
<span style="margin-left: 5%; font-size: 25px; font-family: Tahoma, Geneva, sans-serif;">Dicke: </span>
<select id="graph_editor_thickness">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
</select>
<input id="graph_editor_input" type="text"/>
<input id="graph_editor_done" onclick="currentEditor.editDone()" type="button" value="OK"/>
</div>
</div>
</body>
</html>

@ -0,0 +1,259 @@
function Editor(obj, i) {
var x = ($(obj).offset().left * 2 + $(obj).width()) / 2;
var y = ($(obj).offset().top * 2 + $(obj).height()) / 2;
$("#graph_editor").css({
"left": x,
"top": y
});
$("#graph_editor_thickness").val(graphs[i].getThickness());
$("#graph_editor_input").val(graphs[i].getDisplayFunction());
$("#graph_editor_wrapper").show();
editing = true;
this.colorPicker = new ColorPicker(this);
this.colorPicker.hex = graphs[i].getColor();
this.colorPicker.updateFromHEX(null, true);
this.editDone = function(){
var newFunc = $("#graph_editor_input").val();
graphs[i].setDisplayFunction(newFunc);
graphs[i].setColor(this.colorPicker.getColor());
graphs[i].setThickness(parseInt($("#graph_editor_thickness").val()));
$("#function_input").val(graphs[i].getFullDescription());
$("#visible_" + i).css({
"background-color": graphs[i].getColor(),
"border-color": graphs[i].getColor()
});
$("#graph_editor_wrapper").hide();
editing = false;
updateAll();
}
}
function ColorPicker(editor) {
this.movingObject = "";
this.updateFromHSV = function(){
this.h = 1 - $("#hue_picker").position().top / $("#hue").height();
this.s = ($("#sb_picker").position().left + 8) / $("#saturation").width();
this.v = 1 - ($("#sb_picker").position().top + 8) / $("#value").height();
this.r = HSVtoRGB(this.h, this.s, this.v).r;
this.g = HSVtoRGB(this.h, this.s, this.v).g;
this.b = HSVtoRGB(this.h, this.s, this.v).b;
this.hex = RGBtoHEX(this.r, this.g, this.b);
this.updateInterface();
}
this.updateFromRGB = function(){
this.r = $($(".color_picker_rgb")[0]).val();
this.g = $($(".color_picker_rgb")[1]).val();
this.b = $($(".color_picker_rgb")[2]).val();
this.h = RGBtoHSV(this.r, this.g, this.b).h;
this.s = RGBtoHSV(this.r, this.g, this.b).s;
this.v = RGBtoHSV(this.r, this.g, this.b).v;
this.hex = RGBtoHEX(this.r, this.g, this.b);
this.updateFromHEX(null, true);
this.updateInterface();
}
this.updateFromHEX = function(input, otf){
if (!otf){ //Not on the fly
if (isValidHEX($(input).val())) this.hex = $(input).val();
else {
alert("Error!");
return;
}
}
this.r = HEXtoRGB(this.hex).r;
this.g = HEXtoRGB(this.hex).g;
this.b = HEXtoRGB(this.hex).b;
this.h = RGBtoHSV(this.r, this.g, this.b).h;
this.s = RGBtoHSV(this.r, this.g, this.b).s;
this.v = RGBtoHSV(this.r, this.g, this.b).v;
this.updateInterface();
}
this.updateInterface = function(){
var o = Math.round((this.r * 299 + (this.g * 587) + (this.b * 114)) / 1000); //https://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
this.fontColor = (o > 125) ? "#000" : "#FFF";
$($(".color_picker_rgb")[0]).val(this.r);
$($(".color_picker_rgb")[1]).val(this.g);
$($(".color_picker_rgb")[2]).val(this.b);
$("#color_picker_hex").val(this.hex);
$("#hue_picker").css("top", (1 - this.h) * $("#hue").height());
$("#sb_picker").css({
"left": this.s * $("#saturation").width() - 8,
"top": (1 - this.v) * $("#value").height() - 8
});
var sRGB = HSVtoRGB(this.h, 1, 1);
var saturationBackground = "linear-gradient(to right, #FFF 0%, rgb("
+ sRGB.r + ","
+ sRGB.g + ","
+ sRGB.b + ") 100%)";
$("#saturation").css("background", saturationBackground);
/*$($(".color_picker_rgb")[0]).css({
"background-color": "rgb(" + this.r + ", 0, 0)"
});
$($(".color_picker_rgb")[1]).css({
"background-color": "rgb(0, " + this.g + ", 0)"
});
$($(".color_picker_rgb")[2]).css({
"background-color": "rgb(0, 0, " + this.b + ")"
});*/
//Fancy but overloaded
$("#color_picker_hex").css({
"background-color": this.hex,
"color": this.fontColor
});
}
this.mousePressed = function(){
var x = winMouseX - $("#saturation").offset().left;
var y = winMouseY - $("#value").offset().top;
if (x > 0 && x < $("#saturation").width() && y > 0 && y < $("#value").height()){
this.movingObject = "sb";
}
if (x > $("#saturation").width() + 6 && x < $("#saturation").width() + 6 + $("#hue").width() && y > 0 && y < $("#hue").height()){
this.movingObject = "hue";
}
this.mouseDragged();
}
this.mouseDragged = function(){
if (this.movingObject == "hue"){
var objH = $("#hue");
var picker = $("#hue_picker");
var h = winMouseY - objH.offset().top;
if (h > 0 && h < objH.height()){
picker.css("top", h - 1);
} else if (h > objH.height()){
picker.css("top", objH.height() - 1);
} else if (h < 0){
picker.css("top", -1);
}
}
if (this.movingObject == "sb"){
var objS = $("#saturation");
var objV = $("#value");
var picker = $("#sb_picker");
var s = winMouseX - objS.offset().left;
var v = winMouseY - objV.offset().top;
if (s > 0 && s < objS.width()){
picker.css("left", s - 8);
} else if (s < 0){
picker.css("left", -8);
} else if (s < objS.width()){
picker.css("left", objS.width() - 8);
}
if (v > 0 && v < objV.height()){
picker.css("top", v - 8);
} else if (v < 0){
picker.css("top", -8);
} else if (v > objV.height()){
picker.css("top", objV.height() - 8);
}
}
this.updateFromHSV();
}
this.mouseReleased = function(){
this.movingObject = "";
}
this.getColor = function(){
return this.hex;
}
}
//www.stackoverflow.com -->
function RGBtoHEX(r, g, b) {
var rgb = b | (g << 8) | (r << 16);
return '#' + (0x1000000 + rgb).toString(16).slice(1);
}
function HEXtoRGB(hex) {
var shorthandRegex = /^#?([a-fA-F\d])([a-fA-F\d])([a-fA-F\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
if (arguments.length === 1) {
s = h.s, v = h.v, h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
function RGBtoHSV(r, g, b) {
if (arguments.length === 1) {
g = r.g, b = r.b, r = r.r;
}
var max = Math.max(r, g, b), min = Math.min(r, g, b),
d = max - min,
h,
s = (max === 0 ? 0 : d / max),
v = max / 255;
switch (max) {
case min: h = 0; break;
case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;
case g: h = (b - r) + d * 2; h /= 6 * d; break;
case b: h = (r - g) + d * 4; h /= 6 * d; break;
}
return {
h: h,
s: s,
v: v
};
}
function isValidHEX(hex){
return /(^#[0-9A-Fa-f]{6}$)|(^#[0-9A-Fa-f]{3}$)/i.test(hex);
}

@ -0,0 +1,59 @@
function Graph(fullDescription) {
var d = fullDescription;
this.name = d.substring(0, d.indexOf("("));
this.reference = d.charAt(d.indexOf("(") + 1);
this.displayFunction = d.substring(d.indexOf("=") + 1, d.length);
this.color = "#000000";
this.thickness = 2;
this.points = [];
this.visible = true;
this.getFullDescription = function(){
return (this.name + "(" + this.reference + ") = " + this.displayFunction).replace(/\s+/g, " ");
}
this.getDisplayFunction = function(){return this.displayFunction;}
this.setDisplayFunction = function(displayFunction){
this.displayFunction = displayFunction.replace(/\s+/g, " ");
this.convertToExecuteableFunction();
}
this.getExecuteFunction = function(){return this.executeFunction;}
this.getReference = function(){return this.reference;}
this.getName = function(){return this.name;}
this.getColor = function(){return this.color;}
this.setColor = function(color){this.color = color;}
this.getThickness = function(){return this.thickness;}
this.setThickness = function(thickness){this.thickness = thickness;}
this.getPoints = function(){return this.points;}
this.setPoints = function(points){this.points = points;}
this.convertToExecuteableFunction = function(){
var f = this.displayFunction;
f = f.substr(0, f.length);
f = f.replace(/,/g, ".");
f = f.replace(/(\d+\.?\d*)\s*([a-z])/g, "$1*$2");
f = f.replace(/([a-z])\s*(\d+\.?\d*)/g, "$2*$1");
f = f.replace(/\-([a-z])/g, "-1*$1");
f = f.replace(new RegExp("([a-z])" + this.reference, "g"), "$1*" + this.reference);
f = f.replace(new RegExp(this.reference + "([a-z])", "g"), "$1*" + this.reference);
variables.forEach(function(v){f = f.replace(new RegExp(v.getName(), "g"), v.getValue());});
var powCount = f.split("^").length - 1;
for (var i = 0; i < powCount; i++){f = f.replace(/(\(.*(\(.*\))*.*\)|[a-z]?(\d+\.?\d*)?)\^(\(.*(\(.*\))*.*\)|[a-z]?(\d+\.?\d*)?)/, "pow($1, $4)");}
f = f.replace(/\|(.+)\|/g, "abs($1)");
f = f.replace(/e/g, "Math.E");
//console.log(f);
this.executeFunction = f;
}
this.convertToExecuteableFunction();
}

@ -0,0 +1,38 @@
function restoreSettings(){
for (var i = 0; i < Infinity; i++){
if (getItem("fullDescription" + i) == null) break;
var g = new Graph(getItem("fullDescription" + i));
g.name = getItem("name" + i);
g.reference = getItem("reference" + i);
g.displayFunction = getItem("displayFunction" + i);
g.executeFunction = getItem("executeFunction" + i);
g.color = getItem("color" + i);
g.thickness = int(getItem("thickness" + i));
g.visible = boolean(getItem("visible" + i));
graphs.push(g);
}
}
function safeSettings(){
}
function restoreStandard(){
if (graphs.length > 0){return;}
function restore(f, c, i){
var g = new Graph(f);
g.setColor(c);
graphs[i] = g;
}
restore("f(x)=x^3-2x", "#ffe602", 0);
restore("g(x)=(1 - x^2)^(1/2)", "#ff0202", 1);
restore("h(x)=e^(-x)", "#000000", 2);
restore("i(x)= 1/(x^2)", "#31ff04", 3);
restore("j(x)= |x| * x", "#0f02ff", 4);
restore("k(x)=log(x)", "#ff0be2", 5);
restore("l(x)= sin(2x)", "#02ffc6", 6);
restore("m(x)=cos(0.5x)", "#ff8d03", 7);
restore("n(x)=atan(x)", "#01cfff", 8);
}

@ -0,0 +1,17 @@
function Variable(name, value){
this.name = name;
this.value = value;
this.slider = new Slider(this);
this.getName = function(){return this.name;}
this.setName = function(name){this.name = name;}
this.getValue = function(){return this.value;}
this.setValue = function(value_obj, bool){
}
}
function Slider(variable){
this.variable = variable;
}

@ -0,0 +1,357 @@
var TOP = 1;
var RIGHT = 2
var BOTTOM = 3;
var LEFT = 4;
var TOP_RIGHT = 5;
var BOTTOM_RIGHT = 6;
var BOTTOM_LEFT = 7;
var TOP_LEFT = 8;
var wWidth = window.innerWidth;
var wHeight = window.innerHeight;
var oldWHeight;
var oldWWidth;
function updateVars(){
oldWWidth = wWidth;
oldWHeight = wHeight;
wWidth = window.innerWidth;
wHeight = window.innerHeight;
}
function collisionDetection(obj0, obj1){
var sp = strokePadding;
if (obj0.isEllipse && obj1.isRectangle){
//Ball
var b = obj0;
//Rectangle
var r = obj1;
for (var i = 0; i < TWO_PI; i += PI / 32){
/* Check every borderpoint of the ball beginning
at the top in clock direction up to top again */
// Ball Center X
var bcx = b.x;
// Ball Center Y
var bcy = b.y;
// Ball Border X
var bbx = b.x + sin(i) * b.radius;
// Ball Border Y inverted because Y = 0 is the TOP of the screen
var bby = b.y - cos(i) * b.radius;
// Rectangle Width
var rW = r.width + 2 * sp;
// Rectangle Height
var rH = r.height + 2 * sp;
// Rectangle Border X
var rX = r.x - sp;
// Rectangle Border Y
var rY = r.y - sp;
// Objects touch
if (bbx > rX && bbx < rX + rW
&& bby > rY && bby < rY + rH){
// STRAIGHT FACES //
//Top/Bottom touch
if (bcx > rX && bcx < rX + rW){
//Top touch
if (b.v.y > 0) return {isTouching: true, location: TOP};
//Bottom touch
if (b.v.y < 0) return {isTouching: true, location: BOTTOM};
}
//Left/Right touch
if (bcy > rY && bcy < rY + rH){
//Left touch
if (b.v.x > 0) return {isTouching: true, location: LEFT};
//Right touch
if (b.v.x < 0) return {isTouching: true, location: RIGHT};
}
// CORNERS //
// BOTTOM Left/Right
if (i > 0 && i <= PI / 2) return {isTouching: true, location: BOTTOM_LEFT};
//LEFT Bottom/Top
if (i > PI / 2 && i <= PI) return {isTouching: true, location: TOP_LEFT};
//TOP Left/Right
if (i > PI && i <= PI + PI / 2) return {isTouching: true, location: TOP_RIGHT};
//RIGHT Bottom/Top
if (i > PI + PI / 2 && i <= TWO_PI) return {isTouching: true, location: BOTTOM_RIGHT};
}
}
}
if (obj0.isEllipse && obj1.isEllipse){
//Ball 1
var b1 = obj0;
//Ball 2
var b2 = obj1;
//Balls are close to each other
if (b1.x + b1.radius > b2.x - b2.radius
&& b1.x - b1.radius < b2.x + b2.radius
&& b1.y + b1.radius > b2.y - b2.radius
&& b1.y - b1.radius < b2.y + b2.radius){
var distance = sqrt(pow(b1.x - b2.x, 2) + pow(b1.y - b2.y, 2));
if (distance < b1.radius + b2.radius) return {isTouching: true};
}
}
return {isTouching: false, location: 0};
}
function performCollision(obj0, obj1, collision){
if (obj0.isEllipse){
var ball = obj0;
//Ball collides with frameborder
if (obj1.isFrameborder){
switch (collision.location){
case BOTTOM:
ball.v.y *= -1;
break;
case LEFT:
case RIGHT:
ball.v.x *= -1;
break;
}
if (testMode && collision.location == TOP) ball.v.y *= -1;
ball.move();
}
//Ball collides with any brick
if (obj1.isBrick){
switch (collision.location){
case TOP:
case BOTTOM:
ball.v.y *= -1;
ball.move();
return;
case LEFT:
case RIGHT:
ball.v.x *= -1;
ball.move();
return;
case TOP_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y;
break;
case TOP_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y;
break;
case BOTTOM_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y + obj1.height;
break;
case BOTTOM_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y + obj1.height;
break;
}
var nx = ball.x - cornerX;
var ny = ball.y - cornerY;
var length = sqrt(nx * nx + ny * ny);
nx /= length;
ny /= length;
var projection = ball.v.x * nx + ball.v.y * ny;
ball.v.x = ball.v.x - 2 * projection * nx;
ball.v.y = ball.v.y - 2 * projection * ny;
ball.move();
}
//Ball collides with paddleboard
if (obj1.isPaddle){
switch (collision.location){
case TOP:
case TOP_LEFT:
case TOP_RIGHT:
ball.v.x = ball.calcVelocityX(obj1, ball.v.x);
ball.v.y = -ball.calcVelocityY();
ball.move();
return;
case LEFT:
case RIGHT:
ball.v.x *= -1;
ball.move();
return;
case BOTTOM_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y + obj1.height;
break;
case BOTTOM_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y + obj1.height;
break;
}
var nx = ball.x - cornerX;
var ny = ball.y - cornerY;
var length = sqrt(nx * nx + ny * ny);
nx /= length;
ny /= length;
var projection = ball.v.x * nx + ball.v.y * ny;
ball.v.x = ball.v.x - 2 * projection * nx;
ball.v.y = ball.v.y - 2 * projection * ny;
ball.move();
}
//Ball collides with other ball
if (obj1.isEllipse){
//Ball 1
var b1 = obj0;
//Ball 2
var b2 = obj1;
//Set mass equal to radius of each ball
b1.mass = b1.radius;
b2.mass = b2.radius;
//Colliding angle of ball 1 to ball 2 using arc tan of both x and y differences
var collisionAngle = atan2((b2.y - b1.y), (b2.x - b1.x));
//Converting directions of velocity vector of balls into angles
var d1 = atan2(b1.v.y, b1.v.x);
var d2 = atan2(b2.v.y, b2.v.x);
//Ignoring mass effects new velocites are simply magnitude multiplied with value of angle differences
var newXspeed1 = b1.v.mag * cos(d1 - collisionAngle);
var newYspeed1 = b1.v.mag * sin(d1 - collisionAngle);
var newXspeed2 = b2.v.mag * cos(d2 - collisionAngle);
var newYspeed2 = b2.v.mag * sin(d2 - collisionAngle);
//According to the principle of linear momentum, kinetic energy stays the same after collision, so velocities are now related to masses
var finalXspeed1 = ((b1.mass - b2.mass) * newXspeed1 + b2.mass * 2 * newXspeed2) / (b1.mass + b2.mass);
var finalYspeed1 = newYspeed1;
var finalXspeed2 = (b1.mass * 2 * newXspeed1 + (b2.mass - b1.mass) * newXspeed2) / (b1.mass + b2.mass);
var finalYspeed2 = newYspeed2;
//Values of collisionAngle
var cosAngle = cos(collisionAngle);
var sinAngle = sin(collisionAngle);
//To also keep velocites relative to pure collisionAngle, subtract sin*x from cos*x and add sin*y to cos*y because coordSystem has y = 0 on the top
var u1x = cosAngle * finalXspeed1 - sinAngle * finalYspeed1;
var u1y = sinAngle * finalXspeed1 + cosAngle * finalYspeed1;
var u2x = cosAngle * finalXspeed2 - sinAngle * finalYspeed2;
var u2y = sinAngle * finalXspeed2 + cosAngle * finalYspeed2;
//Set new velocities to both balls
b1.v.x = u1x;
b1.v.y = u1y;
b2.v.x = u2x;
b2.v.y = u2y;
//Update magnitude
b1.v.mag = sqrt(pow(b1.v.x, 2) + pow(b1.v.y, 2));
b2.v.mag = sqrt(pow(b2.v.x, 2) + pow(b2.v.y, 2));
//Move balls one vx/vy forward to avoid double inverting collision detection
b1.x += b1.v.x;
b1.y += b1.v.y;
b2.x += b2.v.x;
b2.y += b2.v.y;
}
}
}
function toTimeString(time, hoursWanted){
var time = floor(time / 10);
var hs = String(floor(time % 100));
var fs = String(floor((time / 100) % 60));
if (hoursWanted){
var min = String(floor(((time / 100) / 60) % 60));
var hr = String(floor(((time / 100) / 60) / 60));
if (hs.length < 2) hs = "0" + hs;
if (fs.length < 2) fs = "0" + fs;
if (min.length < 2) min = "0" + min;
if (hr.length < 2) hr = "0" + hr;
var timeString = hr + ":" + min + ":" + fs + ":" + hs;
} else {
var min = String(floor(((time / 100) / 60) % 60));
if (hs.length < 2) hs = "0" + hs;
if (fs.length < 2) fs = "0" + fs;
if (min.length < 2) min = "0" + min;
var timeString = min + ":" + fs + ":" + hs;
}
return timeString;
}
function setCookie(name, value, years){
var expires = "";
if (years){
var date = new Date();
date.setTime(date.getTime() + (years * 365 * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + value + expires + "; path=/";
}
function getCookie(name){
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++){
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function deleteCookies(){
for (var i = 0; i < arguments.length; i++) setCookie(arguments[i], "", -1);
}
function deleteAllCookies(){
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) deleteCookies(cookies[i].split("=")[0]);
}

@ -0,0 +1,319 @@
var graphs,
variables,
currentEditor,
maxSquareCount,
minSquareCount,
padding,
paddingFactor,
tickFactor,
textHeight,
paddingDivider,
scrollFactor,
squareCount,
axisDispo,
axisDispoPI,
origin,
distance,
valid,
editing;
function setup(){
frameRate(0);
assignGlobalVariables();
restoreSettings();
//restoreStandard();
prepareVisibilites();
updateAll();
updateScroll();
}
function assignGlobalVariables(){
graphs = [],
variables = [],
currentEditor = null,
maxSquareCount = {x: 20, y: 15},
minSquareCount = {x: 15, y: 10},
squareCount = {x: 0, y: 0},
padding = {x: 50, y: 50},
paddingFactor = {x: 1, y: 1},
paddingDivider = {x: 0, y: 0},
axisDispoPI = {x: false, y: false},
axisDispo = 2,
tickFactor = 1,
origin = {x: 0, y: 0},
distance = {x: 0, y: 0},
textHeight = 15;
}
function addGraph(){
var newGraph = new Graph($("#input").val());
var same = false;
if (newGraph.getName().length == 0) return;
graphs.forEach(function(g){
if (g.getName() == newGraph.getName()){
newGraph.setColor(g.getColor());
newGraph.setThickness(g.getThickness());
graphs[graphs.indexOf(g)] = newGraph;
same = true;
}
});
if (!same){
graphs.push(newGraph);
$("#input").val(newGraph.getFullDescription());
}
updateAll();
}
function updateAll(){
updateInterface();
updateDisplay();
safeSettings();
}
function updateDisplay(){
prepareGridValues();
drawGrid();
drawGraphs();
}
function updateInterface(){
$("#functions").html("");
graphs.forEach(function(g){
var bc = g.getColor();
var c = g.visible ? g.getColor() : "none";
$("#functions").append("<tr><td><div style=\"background-color: " + c + "; border-color: " + bc + "\" onclick=\"toggleGraph(this)\""
+ "></div></td><td><button onclick=\"editGraph(this)\">" + g.getFullDescription()
+ "</button></td><td><button onclick=\"deleteGraph(this)\">X</button></td></tr>");
});
}
function prepareGridValues(){
squareCount.x = width / padding.x;
squareCount.y = height / padding.y;
while (squareCount.x > maxSquareCount.x){
squareCount.x = round(squareCount.x / axisDispo);
paddingFactor.x *= axisDispo;
padding.x *= axisDispo;
}
while (squareCount.y > maxSquareCount.y){
squareCount.y = round(squareCount.y / axisDispo);
paddingFactor.y *= axisDispo;
padding.y *= axisDispo;
}
while (squareCount.x < minSquareCount.x){
squareCount.x *= axisDispo;
paddingFactor.x /= axisDispo;
padding.x = round(padding.x / axisDispo);
}
while (squareCount.y < minSquareCount.y){
squareCount.y *= axisDispo;
paddingFactor.y /= axisDispo;
padding.y = round(padding.y / axisDispo);
}
squareCount.x = round(squareCount.x);
squareCount.y = round(squareCount.y);
paddingDivider.x = padding.x / paddingFactor.x;
paddingDivider.y = padding.y / paddingFactor.y;
}
function drawGrid(){
clear();
stroke("#000");
strokeWeight(2);
line(0, origin.y, width, origin.y);
line(origin.x, height, origin.x, 0);
strokeWeight(0.25);
var centerX = (origin.x - width / 2) % padding.x + width / 2;
var centerY = (origin.y - height / 2) % padding.y + height / 2;
var x, y, numX, numY, textWidthX, textWidthY, i;
for (i = 0; i < squareCount.x * 2; i++){
x = centerX - squareCount.x * padding.x + padding.x * i;
if (axisDispoPI.x) numX = round((x - origin.x) / padding.x * paddingFactor.x / PI * 100) / 100 + "π";
if (!axisDispoPI.x) numX = round((x - origin.x) / padding.x) * paddingFactor.x;
if (numX == 0 || numX == "0π") numX = "";
line(x, 0, x, height);
textWidthX = textWidth(str(numX));
text(numX, x - textWidthX / 2, origin.y + textHeight / 2, textWidthX, textHeight);
}
for (i = 0; i < squareCount.y * 2; i++){
y = centerY - squareCount.y * padding.y + padding.y * i;
if (axisDispoPI.y) numY = -round((y - origin.y) / padding.y * paddingFactor.y / PI * 100) / 100 + "π";
if (!axisDispoPI.y) numY = -round((y - origin.y) / padding.y) * paddingFactor.y;
if (numY == 0 || numY == "0π") numY = "";
line(0, y, width, y);
textWidthY = textWidth(str(numY));
text(numY, origin.x - textWidthY - textHeight / 2, y - textHeight / 2, textWidthY, textHeight);
}
}
function drawGraphs(){
graphs.forEach(function(g){
if (!g.visible) return;
var rdyFunc = g.getExecuteFunction();
var r = g.getReference();
function f(value){
var y;
var execFunc = rdyFunc.replace(new RegExp(r, "g"), value);
try{y = eval(execFunc);} catch(e){y = null;}
return y;
}
var pointsRange = [], x, y;
for (var px = 0; px <= width; px += tickFactor){
x = (px - origin.x) / paddingDivider.x;
y = f(x);
pointsRange[px / tickFactor] = {x: x, y: y};
}
g.setPoints(pointsRange);
});
graphs.forEach(function(g){
if (!g.visible) return;
var t = g.getThickness(), x, y;
stroke(g.getColor());
strokeWeight(t);
g.getPoints().forEach(function(p){
x = origin.x + p.x * paddingDivider.x;
y = origin.y - p.y * paddingDivider.y;
if (x != null && y != null) line(x, y, x + t / 4, y);
});
//Straight lines instead of points:
/*for (var i = 0; i < g.getPoints().length; i++){
p = g.getPoints()[i];
x1 = origin.x + p.x * paddingDivider.x;
y1 = origin.y - p.y * paddingDivider.y;
try{
x2 = origin.x + g.getPoints()[i + 1].x * paddingDivider.x;
y2 = origin.y - g.getPoints()[i + 1].y * paddingDivider.y;
line(x1, y1, x2, y2);
}catch(e){}
}*/
});
}
function editGraph(obj){
var i = $(obj).parent().parent().index();
obj.blur();
currentEditor = new Editor(obj, i);
}
function deleteGraph(obj){
var i = $(obj).parent().parent().index();
obj.blur();
graphs.splice(i, 1);
updateAll();
}
function toggleGraph(obj){
var i = $(obj).parent().parent().index();
obj.blur();
graphs[i].visible = !graphs[i].visible;
updateAll();
}
function mouseWheel(event){
if (mouseX > 0 && mouseY < height && !editing){
var oldPaddingX = padding.x;
var oldPaddingY = padding.y;
var oldPaddingFactorX = paddingFactor.x;
var oldPaddingFactorY = paddingFactor.y;
padding.x *= (scrollFactor - (event.delta > 0 ? 3 : -3)) / scrollFactor;
padding.y *= (scrollFactor - (event.delta > 0 ? 3 : -3)) / scrollFactor;
padding.x = round(padding.x);
padding.y = round(padding.y);
prepareGridValues();
origin.x = -(mouseX - origin.x) / (oldPaddingX / oldPaddingFactorX) * (padding.x / paddingFactor.x) + mouseX;
origin.y = -(mouseY - origin.y) / (oldPaddingY / oldPaddingFactorY) * (padding.y / paddingFactor.y) + mouseY;
updateDisplay();
}
}
function updateScroll(){
scrollFactor = round((500 - $("#scroll_input").val() * 0.95) / 5);
}
function updateDisposition(obj, xAxis){
obj.blur();
var dispo = $(obj).val();
if (xAxis){
if (dispo == "PI" && !axisDispoPI.x){
paddingFactor.x *= PI;
padding.x *= PI;
axisDispoPI.x = true;
}
if (dispo == "1" && axisDispoPI.x){
paddingFactor.x /= PI;
padding.x /= PI;
axisDispoPI.x = false;
}
}
if (!xAxis){
if (dispo == "PI" && !axisDispoPI.y){
paddingFactor.y *= PI;
padding.y *= PI;
axisDispoPI.y = true;
}
if (dispo == "1" && axisDispoPI.y){
paddingFactor.y /= PI;
padding.y /= PI;
axisDispoPI.y = false;
}
}
updateAll();
}
function mouseDragged(){
if (editing){currentEditor.colorPicker.mouseDragged();}
else if (valid){
origin.x = round(mouseX - distance.x);
origin.y = round(mouseY - distance.y);
updateDisplay();
}
}
function mousePressed(){
if (editing){currentEditor.colorPicker.mousePressed();}
else if (mouseX > 0 && mouseY < height){
valid = true;
distance.x = mouseX - origin.x;
distance.y = mouseY - origin.y;
$("#defaultCanvas0").css("cursor", "all-scroll");
} else {valid = false;}
}
function mouseReleased(){
if (editing){currentEditor.colorPicker.mouseReleased();}
$("#defaultCanvas0").css("cursor", "auto");
}
function prepareVisibilites(){
if (!editing) $("#graph_editor_wrapper").hide();
$("#canvas_holder").css("height", windowHeight - $("#input_holder").outerHeight() + "px");
var canvas = createCanvas(windowWidth - $("#displayer").outerWidth(), windowHeight - $("#input_holder").outerHeight());
canvas.parent("canvas_holder");
$(".holder:not(#settings_holder)").css("height", windowHeight * 0.7 * 0.5 + "px");
$("#settings_holder").css("height", $("#displayer").outerHeight() - $("#function_holder").outerHeight() - $("#variable_holder").outerHeight() - 80 + "px");
origin.x = width / 2;
origin.y = height / 2;
textFont("Arial", textHeight);
$("body").css("background-color", "#FFF");
}

@ -0,0 +1,147 @@
a:link, a:hover, a:active, a:visited{color: #000;}
body, canvas{margin: 0; padding: 0;}
*:not(#input, #graph_editor_input){
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#functions td:nth-child(1){
width: 5%;
}
#functions td:nth-child(1) div{
width: 20px;
height: 20px;
border-width: 3px;
border-style: solid;
border-radius: 50%;
}
#functions td:nth-child(3){
width: 5%;
}
#functions td:nth-child(3) button{
width: 100%;
background-color: #F00;
border: 2px solid #F00;
border-radius: 2px;
}
#input_holder{
position: absolute;
display: block;
bottom: 0;
right: 0;
padding: 5px 0.5% 5px 0.5%;
width: 79%;
height: 30px;
background-color: #777;
}
#input{
width: 95%;
height: 30px;
font-size: 18px;
}
#submit{
width: 4%;
height: 30px;
margin: 0;
padding: 0;
}
#displayer{
position: absolute;
display: block;
background-color: #999;
padding: 0 1% 0 1%;
width: 18%;
height: 100%;
border-right: 5px solid #000;
}
#canvas_holder{
position: absolute;
left: 20%;
width: 80%;
}
.displayer{
width: 100%;
}
.holder{
border: 5px solid #000;
background-color: #777;
overflow-y: auto;
}
#variable_holder{
margin-top: 20px;
margin-bottom: 20px;
}
#settings_holder{
text-align: left;
}
#settings_holder span{
margin: 10px;
}
legend{
font-size: 30px;
}
#scroll_input{
width: calc(100% - 20px);
margin: 10px;
}
.displayer button{
text-align: left;
font-size: 20px;
width: 100%;
padding: 5px;
cursor: pointer;
}
#graph_editor_wrapper{
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
}
#graph_editor{
position: absolute;
width: 400px;
min-height: 400px;
background-color: #BBB;
border-radius: 10px;
border: 4px solid #000;
box-shadow: 10px 10px 10px #000;
}
#graph_editor_thickness{
width: 20%;
height: 25px;
margin-left: 5%;
font-size: 20px;
}
#graph_editor_input{
width: 90%;
height: 30px;
margin: 5%;
font-size: 23px;
}
#graph_editor_done{
width: 80px;
height: 40px;
font-size: 25px;
margin: 20px;
background-color: #99FF99;
float: right;
border: 3px solid #99FF99;
border-radius: 5px;
box-shadow: 2px 2px 5px #000;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Loading…
Cancel
Save