diff --git a/images/bar.png b/images/bar.png new file mode 100755 index 0000000..31c6b56 Binary files /dev/null and b/images/bar.png differ diff --git a/images/drunken.gif b/images/drunken.gif new file mode 100755 index 0000000..f555bb8 Binary files /dev/null and b/images/drunken.gif differ diff --git a/images/drunken.jpg b/images/drunken.jpg new file mode 100755 index 0000000..19f20ae Binary files /dev/null and b/images/drunken.jpg differ diff --git a/images/trans-white.png b/images/trans-white.png new file mode 100755 index 0000000..89ead2d Binary files /dev/null and b/images/trans-white.png differ 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; +}