From f9ef00cf8a106bcf917d0334dcdccd5ff9eeee3c Mon Sep 17 00:00:00 2001 From: overflowerror Date: Sat, 8 Mar 2014 14:21:29 +0100 Subject: [PATCH] first commit --- images/bar.png | Bin 0 -> 1138 bytes images/drunken.gif | Bin 0 -> 3537 bytes images/drunken.jpg | Bin 0 -> 23784 bytes images/trans-white.png | Bin 0 -> 178 bytes index.html | 26 +++ scripts/libs/Debugger.js | 18 ++ scripts/libs/Graphics.js | 177 ++++++++++++++++ scripts/libs/Miscellaneous.js | 50 +++++ scripts/libs/Position.js | 27 +++ scripts/main.js | 371 ++++++++++++++++++++++++++++++++++ scripts/objects/Bar.js | 19 ++ scripts/objects/Drunken.js | 69 +++++++ scripts/objects/Menu.js | 231 +++++++++++++++++++++ scripts/objects/Path.js | 34 ++++ scripts/objects/Popup.js | 154 ++++++++++++++ 15 files changed, 1176 insertions(+) create mode 100755 images/bar.png create mode 100755 images/drunken.gif create mode 100755 images/drunken.jpg create mode 100755 images/trans-white.png create mode 100755 index.html create mode 100755 scripts/libs/Debugger.js create mode 100755 scripts/libs/Graphics.js create mode 100755 scripts/libs/Miscellaneous.js create mode 100755 scripts/libs/Position.js create mode 100755 scripts/main.js create mode 100755 scripts/objects/Bar.js create mode 100755 scripts/objects/Drunken.js create mode 100755 scripts/objects/Menu.js create mode 100755 scripts/objects/Path.js create mode 100755 scripts/objects/Popup.js diff --git a/images/bar.png b/images/bar.png new file mode 100755 index 0000000000000000000000000000000000000000..31c6b56724a5114d328a249c5cfff5ae1954a053 GIT binary patch literal 1138 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 Lq)bWz5dZ)?M5Gud literal 0 HcmV?d00001 diff --git a/images/drunken.jpg b/images/drunken.jpg new file mode 100755 index 0000000000000000000000000000000000000000..19f20aec1d27c4e7786213e091ab7dfa99bdc153 GIT binary patch literal 23784 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 F|Jn4Z<|+UH literal 0 HcmV?d00001 diff --git a/images/trans-white.png b/images/trans-white.png new file mode 100755 index 0000000000000000000000000000000000000000..89ead2d20ef978c48e437e4a88256abe79b7fa5a GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}K#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*x37`TN&n2}-D90{Nxdx@v7EBjqWZgEalgDW2|1BE0@Tq8=H^K)}k z^GX<;i&7IyQd1PlGfOfQ+&z5*!W;R-fr@xNT^vI=t|$Na|G%D(fir_Si{t7J4WI;r Mr>mdKI;Vst05e%GEC2ui literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100755 index 0000000..1fc25df --- /dev/null +++ b/index.html @@ -0,0 +1,26 @@ + + + Drunken Man Simulator + + + + + + + + + + + diff --git a/scripts/libs/Debugger.js b/scripts/libs/Debugger.js new file mode 100755 index 0000000..2992deb --- /dev/null +++ b/scripts/libs/Debugger.js @@ -0,0 +1,18 @@ + +/* + * class for debugging + */ +function Debug () { +} + +// logs status messages with time in console.log +Debug.log = function (source, text) { + var date = new Date(); + var string = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + "." + date.getMilliseconds(); + for (var i = string.length; i < 15; i++) + string += " "; + string += " from " + source + ": " + text + "..."; + console.log(string); +} + +Debug.log("Debug", "module loaded"); diff --git a/scripts/libs/Graphics.js b/scripts/libs/Graphics.js new file mode 100755 index 0000000..763fbbd --- /dev/null +++ b/scripts/libs/Graphics.js @@ -0,0 +1,177 @@ +Debug.log("Graphics", "module loaded"); + +/* + * class for graphic output + */ +function Graphics() { + Debug.log("Graphics", "instance created"); + // some var init + this.zoom = 1; + this.displayPaths = false; + this.displayDistance = false; + this.displayBar = false; + this.displayDrunken = false; + this.drunken = new Drunken(); + this.bar = new Bar(); + this.null = new Position(window.innerWidth / 2, window.innerHeight / 2); +} + +Graphics.prototype.canvas; // contains the canvas element +Graphics.prototype.context; // contains the context for drawing +Graphics.prototype.drunken; // contains the drunken instance +Graphics.prototype.bar; // contains the bar instance +Graphics.prototype.zoom; // contains the current zoom factor +Graphics.prototype.null; // contains the null position +Graphics.prototype.displayPaths; // true, if the path should be drawn +Graphics.prototype.displayDistance; // true, if the distance between bar and drunken should be drawn +Graphics.prototype.displayBar; // true, if the graphical bar should be drawn +Graphics.prototype.displayDrunken; // true, if the graphical drunken should be drawn + +// init function +Graphics.prototype.init = function () { + this.generateHTML(); +} + +// generates basic html +Graphics.prototype.generateHTML = function () { + var container = document.createElement("div"); + container.id = "container"; + var canvas = document.createElement("canvas"); + canvas.id = "canvas"; + canvas.style.backgroundColor = "#becfdf"; + canvas.style.position = "absolute"; + canvas.style.top = "0px"; + canvas.style.left = "0px"; + canvas.style.cursor = "pointer"; + this.canvas = canvas; + this.context = canvas.getContext('2d'); + container.appendChild(canvas); + document.body.appendChild(container); + Debug.log("Graphics", "basic html inserted"); + this.updateStyle(); +} + +// updates styles (called on resize) +Graphics.prototype.updateStyle = function () { + this.canvas.height = window.innerHeight; + this.canvas.width = window.innerWidth; +} + +// draws all +Graphics.prototype.tick = function(path) { + // draws background + this.drawAlphaBackground(); + // moves canvas null position to null position + this.context.translate(this.null.x, this.null.y); + + // display drunken + if (this.displayDrunken) + this.drawDrunken(this.drunken); + else + this.drawDrunkenPoint(this.drunken); + + // displays bar + if (this.displayBar) + this.drawBar(this.bar); + else + this.drawBarPoint(this.bar); + + // displays path + if (this.displayPaths) + this.drawPath(path); + + // displays distance + if (this.displayDistance) + this.drawDistance(); + + // moves canvas null position back to upper left corner + this.context.translate(-this.null.x, -this.null.y); +} + +// draws background +Graphics.prototype.drawAlphaBackground = function() { + this.context.beginPath(); + this.context.fillStyle = "rgba(190, 207, 223, 1)"; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.context.stroke(); +} + +// draws drunken graphical +Graphics.prototype.drawDrunken = function(drunken) { + this.context.save(); + this.context.translate(this.zoom * drunken.position.x, this.zoom * drunken.position.y); + var frameWidth = drunken.image.width / drunken.numberOfFrames; + var frameHeight = drunken.image.height; + var xOffset = frameWidth * drunken.step; + this.context.rotate(drunken.rotation); + this.context.drawImage(drunken.image, xOffset, 0, frameWidth, frameHeight, - frameWidth/ 2 * this.zoom, - frameHeight / 2 * this.zoom, this.zoom * frameWidth, this.zoom * frameHeight); + this.context.stroke(); + this.context.restore(); +} + +// draws drunken +Graphics.prototype.drawDrunkenPoint = function (drunken) { + this.context.beginPath(); + this.context.save(); + this.context.translate(this.zoom * drunken.position.x, this.zoom * drunken.position.y); + this.context.strokeStyle = "#f00"; + this.context.arc(0, 0, drunken.step + 10, 0, Math.PI * 2, true); + this.context.stroke(); + this.context.restore(); +} + +// draws bar graphical +Graphics.prototype.drawBar = function(bar) { + this.context.save(); + this.context.translate(this.zoom * bar.position.x, this.zoom * bar.position.y); + this.context.rotate(bar.rotation); + this.context.drawImage(bar.image, 0, 0, bar.image.width, bar.image.height, - bar.image.width / 2 * this.zoom, - bar.image.height / 2 * this.zoom, this.zoom * bar.image.width, this.zoom * bar.image.height) + this.context.stroke(); + this.context.restore(); +} + +// draws bar +Graphics.prototype.drawBarPoint = function (bar) { + this.context.beginPath(); + this.context.save(); + this.context.translate(this.zoom * bar.position.x, this.zoom * bar.position.y); + this.context.strokeStyle = "#00f"; + this.context.arc(0, 0, 15 - this.drunken.step, 0, Math.PI * 2, true); + this.context.stroke(); + this.context.restore(); +} + +// default/begin image +Graphics.prototype.drawDefault = function () { + // pointless at the moment + // but maybe used in a later version +} + +// draws path +Graphics.prototype.drawPath = function(path) { + this.context.save(); + this.context.beginPath(); + this.context.lineCap = "round"; + this.context.strokeStyle = "#fff"; + var old = path.positions[0]; + for (var i = 1; i < path.positions.length; i++) { + this.context.moveTo(old.x * this.zoom, old.y * this.zoom); + var now = path.positions[i]; + this.context.lineTo(now.x * this.zoom, now.y * this.zoom); + old = now; + } + this.context.stroke(); + this.context.restore(); +} + +// draws distance +Graphics.prototype.drawDistance = function () { + this.context.save(); + this.context.beginPath(); + this.context.lineCap = "round"; + this.context.strokeStyle = "#f00"; + this.context.moveTo(0, 0); + this.context.lineTo(this.drunken.position.x * this.zoom, this.drunken.position.y * this.zoom); + this.context.stroke(); + this.context.restore(); +} diff --git a/scripts/libs/Miscellaneous.js b/scripts/libs/Miscellaneous.js new file mode 100755 index 0000000..6270a55 --- /dev/null +++ b/scripts/libs/Miscellaneous.js @@ -0,0 +1,50 @@ +Debug.log("Miscellaneous", "module loaded"); + +/* + * calculates page loading time + */ +function calcLoadTime() { + var startTime = new Date().getTime(); + window.setTimeout(function() { + var endTime = new Date().getTime(); + var time = endTime - startTime; + Miscellaneous.prototype.loadTime = time; + Debug.log("Miscellaneous", "page loading time calculated: " + time + "ms"); + }, 0); +} +calcLoadTime(); +// removes function +calcLoadTime = null; + +// add static mathode sign to Math class +Math.sign = function(x) { + return (x > 0) ? 1 : (x < 0) ? -1 : 0; +} + +/* + * class for all functions, which don't fit into other classes + */ +function Miscellaneous () { + Debug.log("Miscellaneous", "instance created"); +} + +// include function +// includes file and excecuts load once the file is fully loaded, parsed and useable +Miscellaneous.prototype.include = function (file, load) { + var script = document.createElement("script"); + script.type = "text/javascript"; + script.onload = load; + script.src = file; + document.head.appendChild(script); + Debug.log("Miscellaneous", "file included \"" + file + "\""); +} + +// this function get's sopported style props +// used for css3 manipulation in javascript +Miscellaneous.prototype.getsupportedprop = function (proparray) { + var root = document.documentElement; + for (var i = 0; i < proparray.length; i++) + if (typeof root.style[proparray[i]] == "string") + return proparray[i] +} + diff --git a/scripts/libs/Position.js b/scripts/libs/Position.js new file mode 100755 index 0000000..8be024d --- /dev/null +++ b/scripts/libs/Position.js @@ -0,0 +1,27 @@ +Debug.log("Position", "module loaded"); + +/* + * position class + */ +function Position(x, y) { + // if arguments x, y are set + if (x) + this.x = x; + else + this.x = 0; + if (y) + this.y = y; + else + this.y = 0; +} + +// yeah +Position.prototype.x; +Position.prototype.y; + +// returns true if argument and this are the same position +Position.prototype.equals = function (position) { + if (this.x == position.x && this.y == position.y) + return true; + return false; +} diff --git a/scripts/main.js b/scripts/main.js new file mode 100755 index 0000000..244c7f5 --- /dev/null +++ b/scripts/main.js @@ -0,0 +1,371 @@ + +/* + * global vars + */ +var lengthOfStep = 10; // distance between edges; in graphical mode -> 40 +var numberOfEdges = 10; // will be set in start dialog +var defTicksPerEdge = 33; // ticks for the drunken man to reach the next edge +var numberOfTicksPerSec = 33; // sets tickrate (= framerate) + +var useTicksPerEdge = defTicksPerEdge; // for "even faster" + +var misc; // contains the Miscellaneous instance +var graphics; // contains the Graphics instance +var menu; // contains the Menu instance +var path; // contains the path for the drunken man + +var edge; // contains the active edge +var ticksPerEdge; // contains the number of ticks to reach the next edge +var tickNum; // contains the global number of ticks +var started; // true, if simulation is started +var paused; // true, if simulation end is reached + +var checked; // contains the number of loaded includes +var neededChecked; // contains the number of includes + +var dragEnabled; // true, if canvas element is clicked +var dragInit; // true, if initial position is not defined yet +var dragPosition; // contains the last mouse position +var tickedDragPosition; // contains activ mouse position + +var tickId; // contains the interval id of the main ticker +var fasterId; // contains the interval if of the "even faster" ticker + +var startpop; // contains the startup dialog +var simTime; // contains the simulation time + +/* + * setup routine + */ +function setup () { + Debug.log("main", "setup routine started"); + + // some var init... + misc = new Miscellaneous(); + checked = 0; + tickNum = 0; + started = false; + paused = false; + edge = 0; + ticksPerEdge = useTicksPerEdge; + dragEnabled = false; + dragInit = false; + fasterId = 0; + simTime = 0; + + // includes for all modules + + neededChecked = 7; + + misc.include("scripts/libs/Graphics.js", check); + misc.include("scripts/libs/Position.js", check); + + misc.include("scripts/objects/Path.js", check); + misc.include("scripts/objects/Menu.js", check); + misc.include("scripts/objects/Drunken.js", check); + misc.include("scripts/objects/Bar.js", check); + misc.include("scripts/objects/Popup.js", check); +} + +/* + * check routine for includes + */ +function check() { + Debug.log("main", "load checked: " + ++checked + "/" + neededChecked); + + // if all modules are loaded execute main routine + if (checked == neededChecked) + main(); +} + +/* + * main routine + */ +function main() { + Debug.log("main", "main routine started"); + + // some other var init + graphics = new Graphics(); + menu = new Menu(); + path = new Path(); + dragPosition = new Position(); + tickedDragPosition = new Position(); + + // module init + graphics.init(); + menu.init(); + + // pointless, because there isn't a default image to draw ; ) + graphics.drawDefault(); + + // set all (most) events + setEvents(); + + // generate startup dialog + startpop = new Popup("Drunken Man Simulator"); + startpop.text = ""; + startpop.text += 'Options:
'; + startpop.text += 'use graphical mode
'; + startpop.text += 'Please select a time:
'; + startpop.text += '
'; + startpop.text += ''; + startpop.display(); +} + +/* + * sets all (most) events + */ +function setEvents() { + window.onmousewheel = scroll; + window.onmousemove = drag; + document.getElementById("canvas").onmousedown = enableDrag; + window.onmouseup = disableDrag; + tickId = window.setInterval(tick, 1000 / numberOfTicksPerSec); + window.setInterval(infoUpdate, 100); + window.onresize = updateAllStyles; +} + +/* + * tick function for "even faster" + */ +function fastTick() { + + // if not started, than do nothing... + if (!started) return; + + // if end not reached + if (edge != numberOfEdges) { + + // calculate new Position and decrement current ticksPerEdge + graphics.drunken.position = graphics.drunken.getNextPosition(path.positions[edge], ticksPerEdge--); + + // calculate rotation for graphical mode + graphics.drunken.rotation = graphics.drunken.getNextRotation(path.positions[edge]); + + // if next edge is reached: increment edge number and reset ticksPerEdge + if (graphics.drunken.position.equals(path.positions[edge])) { + edge++; + ticksPerEdge = useTicksPerEdge; + } + + // calculate steps for animation + graphics.drunken.step = graphics.drunken.frames[parseInt((tickNum / (5)) % graphics.drunken.frames.length)]; + } + + // if end reached stop simulation + if (edge == numberOfEdges) + stopSimulation(); + + // increment tick counter + tickNum++; +} + +/* + * normal tick function + */ +function tick() { + + // the same as fastTick + if (!started) return; + + // if fast tick is disabled + if ((edge != numberOfEdges) && (!fasterId)) { + graphics.drunken.position = graphics.drunken.getNextPosition(path.positions[edge], ticksPerEdge--); + graphics.drunken.rotation = graphics.drunken.getNextRotation(path.positions[edge]); + if (graphics.drunken.position.equals(path.positions[edge])) { + edge++; + ticksPerEdge = useTicksPerEdge; + } + graphics.drunken.step = graphics.drunken.frames[parseInt((tickNum / (5)) % graphics.drunken.frames.length)]; + } + + // drag routine for canvas element + if (!dragPosition.equals(tickedDragPosition)) { + if (!(dragInit)) { + var deltaX = dragPosition.x - tickedDragPosition.x; + var deltaY = dragPosition.y - tickedDragPosition.y; + + // sets null position in graphics + graphics.null.x += deltaX; + graphics.null.y += deltaY; + } else { + dragInit = false; + } + tickedDragPosition.x = dragPosition.x; + tickedDragPosition.y = dragPosition.y; + } + + // update graphics + graphics.tick(path); + + // if end is reached than stop simulation + if (!paused && (edge == numberOfEdges)) + stopSimulation(); + if (!fasterId) + tickNum++; +} + +/* + * scroll function + */ +function scroll(e) { + e = e ? e : window.event; + var wheelData = e.detail ? e.detail : e.wheelDelta; + if (wheelData > 0) + + // on positiv scroll zoom in + graphics.zoom *= 1.1; + else + + // on negativ scroll zomm out + graphics.zoom /= 1.1; +} + +/* + * updates debug box + */ +function infoUpdate() { + var text = ""; + text += "drunken: x=" + graphics.drunken.position.x + " y=" + graphics.drunken.position.y + " rot=" + graphics.drunken.rotation + "
"; + text += "bar: x=" + graphics.bar.position.x + " y=" + graphics.bar.position.y + " rot=" + graphics.bar.rotation + "
"; + text += "edges: " + edge + "/" + numberOfEdges + "
"; + document.getElementById("debugInfo").innerHTML = text; +} + +/* + * enables drag for canvas element + */ +function enableDrag (e) { + dragEnabled = true; + dragInit = true; + document.getElementById("canvas").style.cursor = "move"; +} + +/* + * disables drag for canvas element + */ +function disableDrag () { + dragEnabled = false; + document.getElementById("canvas").style.cursor = "pointer"; +} + +/* + * drag function + */ +function drag (e) { + + // check drag on all popups + Popup.checkDrag(e); + + // check drag for canvas element + if (!dragEnabled) + return; + dragPosition.x = e.clientX; + dragPosition.y = e.clientY; +} + +/* + * select function for start popup + */ +function selectOption (select, other) { + switch(other) { + case 1: + // numberOfEdges = select + Debug.log("main", (numberOfEdges = select) + " edges selected"); + break; + case 0: + var frames; + // frames = select * numberOfTicksPerSec * 60; numberOfEdges = round(frames / defTicksPerEdge) + // select in min + Debug.log("main", select + " minutes selected -> " + (frames = select * numberOfTicksPerSec * 60) + " frames -> " + (numberOfEdges = Math.round(frames / defTicksPerEdge)) + " edges"); + simTime = frames / numberOfTicksPerSec; + break; + + // on other == undefined + default: + var frames; + // if value == 0 -> display other block + if (select.value == 0) { + document.getElementById("other").style.display = "block"; + return; + } + // same as case 1, but select is object + // select.value in min + Debug.log("main", select.value + " minutes selected -> " + (frames = select.value * numberOfTicksPerSec * 60) + " frames -> " + (numberOfEdges = Math.round(frames / defTicksPerEdge)) + " edges"); + simTime = frames / numberOfTicksPerSec; + } + + // if graphical mode, then displayBar, displayDrunken, lengthOfStep = 40 + if (document.getElementById("graphical").checked) { + lengthOfStep = 40; + graphics.displayBar = true; + graphics.displayDrunken = true; + document.getElementById("displayBar").checked = true; + document.getElementById("displayDrunken").checked = true; + } + + // calculate new path + path = new Path(); + path.calculate(0, 0, numberOfEdges - 1); + + // close popup + startpop.close(); + + // start simulation + started = true; +} + +/* + * for the "start simulation" button + */ +function selectOther () { + selectOption(parseInt(document.getElementById("val").value), parseInt(document.getElementById("siz").value)); +} + +/* + * on resize update all styles + */ +function updateAllStyles () { + graphics.updateStyle(); + menu.updateStyle(); +} + +/* + * is called when simulation end is reached + */ +function stopSimulation() { + paused = true; + + // reset all ticks + if (fasterId) { + window.clearInterval(fasterId); + fasterId = 0; + } else { + window.clearInterval(tickId); + tickId = window.setInterval(tick, 1000 / numberOfTicksPerSec); + } + + // yeah, what do you think? + generateEndPopup(); +} + +/* + * generate the popup for the end + */ +function generateEndPopup () { + var endPop = new Popup("simulation report"); + endPop.text = ""; + // if simulation time is set -> display time & frames + if (simTime) { + endPop.text += "simulation time: " + simTime + "s
"; + endPop.text += "frames: " + simTime * numberOfTicksPerSec + " (@ " + numberOfTicksPerSec + " fps)
"; + } + endPop.text += "edges: " + numberOfEdges + "
"; + endPop.text += "distance: " + Math.sqrt(graphics.drunken.position.x * graphics.drunken.position.x + graphics.drunken.position.y * graphics.drunken.position.y) + "
"; + // calculated distance is the sqrt of time (einstein) + endPop.text += "calculated distance: " + Math.sqrt(path.positions.length); + endPop.display(); +} diff --git a/scripts/objects/Bar.js b/scripts/objects/Bar.js new file mode 100755 index 0000000..248c660 --- /dev/null +++ b/scripts/objects/Bar.js @@ -0,0 +1,19 @@ +Debug.log("Bar", "module loaded"); + +/* + * class for the bar + */ +function Bar () { + Debug.log("Bar", "instance created"); + this.position = new Position(); + this.rotation = 0; + this.image = new Image(); + this.image.src = "images/bar.png"; +} + +// image for graphics +Bar.prototype.image; +// rotaion for graphics +Bar.prototype.rotation; +// position +Bar.prototype.position; diff --git a/scripts/objects/Drunken.js b/scripts/objects/Drunken.js new file mode 100755 index 0000000..2ac8d29 --- /dev/null +++ b/scripts/objects/Drunken.js @@ -0,0 +1,69 @@ +Debug.log("Drunken", "module loaded"); + +/* + * class for the drunken man + */ +function Drunken () { + Debug.log("Drunken", "instance created"); + // some var init + this.step = 1; + this.position = new Position(); + this.rotation = 0; + this.image = new Image(); + this.image.src = "images/drunken.gif"; + this.numberOfFrames = 8; + + // definition of the frames (order) + this.frames = Array(); + this.frames[0] = 4; + this.frames[1] = 3; + this.frames[2] = 2; + this.frames[3] = 1; + this.frames[4] = 0; + this.frames[5] = 1; + this.frames[6] = 2; + this.frames[7] = 3; + this.frames[8] = 4; + this.frames[9] = 5; +} + +// rotation for graphics +Drunken.prototype.rotation; +// position +Drunken.prototype.position; +// current animation step +Drunken.prototype.step; +// how many frames does the animation have? +Drunken.prototype.numberOfFrames; +// array for the frame order +Drunken.prototype.frames; + +// calculates new position and returns it +Drunken.prototype.getNextPosition = function(nextEdge, ticksToNext) { + /* safty first */ + if (ticksToNext < 0) { + this.position = nextEdge; + return this.position; + } + + // split distance to x,y + var deltaX = nextEdge.x - this.position.x; + var deltaY = nextEdge.y - this.position.y; + // calulate step width for next tick + var xPerTick = deltaX / ticksToNext; + var yPerTick = deltaY / ticksToNext; + // create new position instance with new coordinates + return new Position(xPerTick + this.position.x, yPerTick + this.position.y); +} + +// calculates new rotation and returns it +Drunken.prototype.getNextRotation = function(nextEdge) { + var deltaX = nextEdge.x - this.position.x; + var deltaY = nextEdge.y - this.position.y; + var direct = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + if (direct == 0) + var rot = 0; + else + var rot = Math.acos(deltaX / direct) * Math.sign(deltaY) - Math.PI / 2; + return rot; +} diff --git a/scripts/objects/Menu.js b/scripts/objects/Menu.js new file mode 100755 index 0000000..2c6fe9e --- /dev/null +++ b/scripts/objects/Menu.js @@ -0,0 +1,231 @@ +Debug.log("Menu", "module loaded"); + +/* + * class for menu and basic html + */ +function Menu() { + Debug.log("Menu", "instance created"); +} + +// contains the dropdown dom object +Menu.prototype.dropDown; +// is the dropdown menu collapsed +Menu.prototype.folded = true; + +// init +Menu.prototype.init = function () { + this.generateHTML(); +} + +// generates basic HTML and inserts it +Menu.prototype.generateHTML = function () { + var container = document.createElement("div"); + container.id = "menuContainer"; + container.style.backgroundColor = "#19446b"; + container.style.position = "absolute"; + container.style.height = "25px"; + container.style.top = "0px"; + container.style.left = "0px"; + document.body.appendChild(container); + + var dropDown = document.createElement("div"); + dropDown.id = "menuDropDown"; + dropDown.style.width = "200px"; + dropDown.style.height = "25px"; + dropDown.style.position = "absolute"; + dropDown.style.top = "0px"; + dropDown.style.overflow = "hidden"; + dropDown.style.left = "0px"; + dropDown.style.backgroundColor = "#6395c4"; + container.appendChild(dropDown); + this.dropDown = dropDown; + + var dropDownButton = document.createElement("div"); + dropDownButton.innerHTML = "Debug Settings"; + dropDownButton.onclick = menu.fold; + dropDownButton.style.backgroundColor = "#4d7ba5"; + dropDownButton.style.height = "25px"; + dropDown.appendChild(dropDownButton); + + var dropDownControls = document.createElement("div"); + dropDownControls.id = "dropdownControls"; + dropDownControls.style.position = "relative"; + dropDownControls.style.left = "0px"; + dropDown.appendChild(dropDownControls); + + var tmpDiv = document.createElement("div"); + var check = document.createElement("input"); + check.id = "displayDebug"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "display debug info"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("displayDebug").onclick = menu.debugCheck; + + tmpDiv = document.createElement("div"); + check = document.createElement("input"); + check.id = "displayPath"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "display path"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("displayPath").onclick = menu.pathCheck; + + tmpDiv = document.createElement("div"); + check = document.createElement("input"); + check.id = "displayDistance"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "display distance to bar"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("displayDistance").onclick = menu.distanceCheck; + + tmpDiv = document.createElement("div"); + check = document.createElement("input"); + check.id = "displayBar"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "display bar"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("displayBar").checked = false; + document.getElementById("displayBar").onclick = menu.barCheck; + + tmpDiv = document.createElement("div"); + check = document.createElement("input"); + check.id = "displayDrunken"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "display drunken"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("displayDrunken").checked = false; + document.getElementById("displayDrunken").onclick = menu.drunkenCheck; + + tmpDiv = document.createElement("div"); + check = document.createElement("input"); + check.id = "fastForward"; + check.type = "checkbox"; + tmpDiv.appendChild(check); + tmpDiv.innerHTML += "fast forward simulation"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("fastForward").setAttribute("onclick", "menu.fastForward();"); + + tmpDiv = document.createElement("div"); + tmpDiv.id = "fasterForwardDiv"; + check = document.createElement("input"); + check.id = "fasterForward"; + check.type = "checkbox"; + check.style.marginLeft = "20px"; + tmpDiv.appendChild(check); + tmpDiv.style.display = "none"; + tmpDiv.innerHTML += "even faster"; + dropDownControls.appendChild(tmpDiv); + document.getElementById("fasterForward").setAttribute("onclick", "menu.fastForward(1);"); + + var reset = document.createElement("button"); + reset.innerHTML = "reset zoom and position"; + reset.style.position = "absolute"; + reset.style.left = "200px"; + reset.onclick = menu.reset; + container.appendChild(reset); + + var debug = document.createElement("div"); + debug.id = "debugInfo"; + debug.style.backgroundColor = "#618bb2"; + debug.style.position = "absolute"; + debug.style.bottom = "0px"; + debug.style.right = "0px"; + debug.style.height = "100px"; + debug.style.width = "300px"; + debug.style.display = "none"; + document.body.appendChild(debug); + + Debug.log("Menu", "basic html inserted"); + this.updateStyle(); +} + +// refreshes values (for onresize) +Menu.prototype.updateStyle = function () { + document.getElementById("menuContainer").style.width = window.innerWidth + "px"; +} + +// function for the "debug info" checkbox +Menu.prototype.debugCheck = function () { + document.getElementById("debugInfo").style.display = document.getElementById("displayDebug").checked ? "block" : "none"; +} + +// function for the "display path" checkbox +Menu.prototype.pathCheck = function () { + graphics.displayPaths = document.getElementById("displayPath").checked; +} + +// function for the "display distance" checkbox +Menu.prototype.distanceCheck = function () { + graphics.displayDistance = document.getElementById("displayDistance").checked; +} + +// function for the "display bar" checkbox +Menu.prototype.barCheck = function () { + graphics.displayBar = document.getElementById("displayBar").checked; +} + +// function for the "display drunken" checkbox +Menu.prototype.drunkenCheck = function () { + graphics.displayDrunken = document.getElementById("displayDrunken").checked; +} + +// function for "fast forward simulation" and "even faster" +Menu.prototype.fastForward = function (faster) { + if (faster) { + if (fasterId) { + // clear faster tick interval + // and set normal tick to fast mode + useTicksPerEdge = defTicksPerEdge; + window.clearInterval(fasterId); + fasterId = 0; + menu.fastForward(); + document.getElementById("fastForward").disabled = false; + } else { + // set normal tick to normal mode + // and set faster tick interval + useTicksPerEdge = defTicksPerEdge / 5; + fasterId = window.setInterval(fastTick, 1); + window.clearInterval(tickId); + tickId = window.setInterval(tick, 1000 / numberOfTicksPerSec); + document.getElementById("fastForward").disabled = true; + } + return; + } + + // if fast forward is checked switch normal tick to fast mode + // and display "even faster" checkbox + if (document.getElementById("fastForward").checked) { + window.clearInterval(tickId); + tickId = window.setInterval(tick, 10); + document.getElementById("fasterForwardDiv").style.display = "block"; + // else switch normal tick to normal mode + // and hide "ven faster" checkbox + } else { + window.clearInterval(tickId); + tickId = window.setInterval(tick, 1000 / numberOfTicksPerSec); + document.getElementById("fasterForwardDiv").style.display = "none"; + } +} + +// function for the reset button +// resets zoom and centers null position +Menu.prototype.reset = function () { + graphics.zoom = 1; + graphics.null = new Position(window.innerWidth / 2, window.innerHeight / 2); +} + +// function for the dropdown menu +// collaps the dropdown menu +Menu.prototype.fold = function () { + if (menu.folded) + menu.dropDown.style.height = "auto"; + else + menu.dropDown.style.height = "25px"; + menu.folded = !menu.folded; + + Debug.log("Menu", "dropdown menu is " + (menu.folded ? "closed" : "opened")); +} diff --git a/scripts/objects/Path.js b/scripts/objects/Path.js new file mode 100755 index 0000000..0709400 --- /dev/null +++ b/scripts/objects/Path.js @@ -0,0 +1,34 @@ +Debug.log("Path", "module loaded"); + +/* + * class for paths + */ +function Path() { + this.positions = new Array(); + Debug.log("Path", "instance created"); +} + +// contains edge array +Path.prototype.positions; + +// calculates new edges and adds them to positions +// params: x, y -> start point +// length -> number of random points to add +Path.prototype.calculate = function (x, y, length) { + var position = new Position(x, y); + this.positions.push(position); + for (var i = 0; i < length; i++) { + position = this.getNext(position); + this.positions.push(position); + } + Debug.log("Path", "new path calculated"); +} + +// calculates next point +Path.prototype.getNext = function (oldPosition) { + var rotation = Math.random() * 2 * Math.PI; + var result = new Position(); + result.x = parseInt(Math.cos(rotation) * lengthOfStep + oldPosition.x); + result.y = parseInt(Math.sin(rotation) * lengthOfStep + oldPosition.y); + return result; +} diff --git a/scripts/objects/Popup.js b/scripts/objects/Popup.js new file mode 100755 index 0000000..c5997e3 --- /dev/null +++ b/scripts/objects/Popup.js @@ -0,0 +1,154 @@ +Debug.log("Popup", "module loaded"); + +/* + * class for dialogs + */ +// contructor argument is title of popup +function Popup(title) { + Debug.log("Popup", "'" + title + "': instance created"); + + // some var init + this.title = title; + this.height = 400; + this.width = 400; + this.drag = false; + this.id = Popup.getId(); + this.type = Popup.types.normal; + Popup.add(this); +} + +// static field with references to all popups +Popup.array = new Array(); + +// static array (enum) for popup types (not implemented) +Popup.types = { + normal: 1, + normalOkay: 2 +} + +// add popup to array +Popup.add = function (popup) { + Popup.array.push(popup); +} + +// get next id +Popup.getId = function () { + return Popup.array.length; +} + +// static function for handling drag +// called on mousemove +// argument is event object +Popup.checkDrag = function (e) { + for(var i in Popup.array) { + if (Popup.array[i].drag) + Popup.array[i].move(e); + } +} + +// enables drag for popup id (argument) +// called on mousedown on title bar +Popup.enableDrag = function (id) { + Debug.log("Popup", "id " + id + " drag enabled"); + Popup.array[id].drag = true; + Popup.array[id].style.cursor = "move"; +} + +// diables drag for popup id (argument) +// called on mouseup on title bar +Popup.disableDrag = function (id) { + Debug.log("Popup", "id " + id + " drag disabled"); + Popup.array[id].drag = false; + Popup.array[id].dragedPosition = false; + Popup.array[id].style.cursor = "pointer"; +} + +// closes popup id (argument) +Popup.close = function (id) { + Popup.array[id].close(); +} + +// own id +Popup.prototype.id; +// popup title +Popup.prototype.title; +// popup inner text +Popup.prototype.text; +// popup type (not implemented) +Popup.prototype.type; +// popup height +Popup.prototype.height; +// popup width +Popup.prototype.width; +// contains reference to dom style +Popup.prototype.style; +// true, if drag is enabled +Popup.prototype.drag; +// contains last mouse position +Popup.prototype.dragedPosition; + +// displays popup and generates html +Popup.prototype.display = function() { + this.generateHTML(); + this.style.display = "block"; + Debug.log("Popup", "'" + this.title + "': opened"); +} + +// generates html +Popup.prototype.generateHTML = function() { + Debug.log("Popup", "'" + this.title + "': basic html inserted"); + var div = document.createElement("div"); + this.style = div.style; + div.id = this.id; + div.style.height = this.height + "px"; + div.style.width = this.width + "px"; + div.style.backgroundColor = "#dfe7ee"; + div.style.display = "none"; + div.style.position = "absolute"; + div.style.top = (window.innerHeight / 2 - this.height / 2) + "px"; + div.style.left = (window.innerWidth / 2 - this.width / 2) + "px"; + div.style.cursor = "pointer"; + var taskbar = document.createElement("div"); + taskbar.className = "bar"; + taskbar.style.height = "20px"; + taskbar.style.width = this.width + "px"; + taskbar.style.backgroundColor = "#20588b"; + taskbar.style.position = "absolute"; + taskbar.style.top = 0; + taskbar.style.left = 0; + taskbar.innerHTML = '[x] ' + this.title; + div.appendChild(taskbar); + var text = document.createElement("div"); + text.style.position = "absolute"; + text.style.top = "20px"; + text.innerHTML = this.text; + div.appendChild(text); + document.body.appendChild(div); + + var bar = document.getElementById(this.id + "").getElementsByClassName("bar")[0]; + + // small hack for static function params + bar.onmousedown = eval("(function () { Popup.enableDrag(" + this.id + ")})"); + bar.onmouseup = eval("(function () { Popup.disableDrag(" + this.id + ")})"); +} + +// hiddes popup +Popup.prototype.close = function () { + Debug.log("Popup", "'" + this.title + "': closed") + this.style.display = "none"; +} + +// moves popup +// argument is event object +Popup.prototype.move = function (e) { + var position = new Position(e.clientX, e.clientY); + if (!this.dragedPosition) { + this.dragedPosition = position; + return; + } + var deltaX = position.x - this.dragedPosition.x; + var deltaY = position.y - this.dragedPosition.y; + this.style.top = (parseInt(this.style.top) + deltaY) + "px"; + this.style.left = (parseInt(this.style.left) + deltaX) + "px"; + this.dragedPosition = position; +}