diff --git a/app.js b/app.js index 8981b46..a038e1e 100644 --- a/app.js +++ b/app.js @@ -1,29 +1,28 @@ "use strict"; +//import * as dat from 'dat.gui' +//import Chart from 'chart.js' // // classes // var World = /** @class */ (function () { - function World(width, height, denisty, framerate, personSize) { + function World(width, height, density, framerate, personSize) { this.graphData = []; this.first = 0; + this.animationRuns = false; this.width = width; this.height = height; - this.denisty = denisty; - this.personCount = Math.round(width * height * denisty); + this.density = density; this.persons = []; this.framerate = 1000 / framerate; this.personSize = personSize; } World.prototype.init = function () { - var body = document.getElementsByTagName("body")[0]; + var body = document.getElementById("container"); var canvasChart = document.createElement('canvas'); canvasChart.id = "chart"; canvasChart.width = 700; canvasChart.height = 700; - canvasChart.style.zIndex = "2"; - canvasChart.style.position = "absolute"; canvasChart.style.border = "1px solid"; - canvasChart.style.marginLeft = this.width + "px"; body.appendChild(canvasChart); this.chart = new Chart(canvasChart, { type: 'line', @@ -88,32 +87,31 @@ var World = /** @class */ (function () { canvas.id = "canvas"; canvas.width = this.width; canvas.height = this.height; - canvas.style.zIndex = "1"; - canvas.style.position = "absolute"; canvas.style.border = "1px solid"; body.appendChild(canvas); - var div = document.createElement('div'); - div.id = "info"; - body.appendChild(div); - document.getElementById("info").innerHTML = "persons: " + this.personCount; + this.load(); + }; + World.prototype.load = function () { + this.first = 0; + this.persons = []; + this.graphData = []; + this.personCount = this.width * this.height * 0.0001 * this.density; for (var a = 0; a < this.personCount; a++) { var person = new Person(randomIntFromInterval(0, this.width), randomIntFromInterval(0, this.height), this.width, this.height, this.infection, this.mobility, "uninfected", this.personSize); this.persons.push(person); } - this.animationStep(); + if (!this.animationRuns) { + this.animationStep(); + this.animationRuns = true; + } }; World.prototype.animationStep = function () { var _this = this; - var runAnimation = false; this.first++; if (this.first == 2) { this.persons[0].state = "infected"; } // - if (this.first < 3) { - runAnimation = true; - } - // var uninfected = 0; var infected = 0; var deceased = 0; @@ -125,7 +123,6 @@ var World = /** @class */ (function () { for (var a = 0; a < this.persons.length; a++) { for (var b = 0; b < this.persons.length; b++) { if (this.persons[a].state == "infected") { - runAnimation = true; var dist = Math.sqrt(Math.pow((this.persons[a].xPosition - this.persons[b].xPosition), 2) + Math.pow((this.persons[a].yPosition - this.persons[b].yPosition), 2)); if (dist < this.persons[a].infection.reach + this.persons[a].size) { if (this.persons[b].state == "uninfected") { @@ -147,7 +144,9 @@ var World = /** @class */ (function () { recovered++; } } - this.graphData.push({ "uninfected": uninfected, "infected": infected, "deceased": deceased, "recovered": recovered }); + if (this.first > 2 && infected > 0) { + this.graphData.push({ "uninfected": uninfected, "infected": infected, "deceased": deceased, "recovered": recovered }); + } //convert data var labels = []; var uninfectedArray = []; @@ -161,7 +160,7 @@ var World = /** @class */ (function () { deceasedArray.push(this.graphData[a].deceased); recoveredArray.push(this.graphData[a].recovered); } - var xaxisstep = 15; + var xaxisstep = 20; labels = convertArrayLenght(labels, xaxisstep); uninfectedArray = convertArrayLenght(uninfectedArray, xaxisstep); infectedArray = convertArrayLenght(infectedArray, xaxisstep); @@ -178,22 +177,15 @@ var World = /** @class */ (function () { this.persons[a].move(); this.persons[a].draw(ctx); } - if (runAnimation) { - setTimeout(function () { - _this.animationStep(); - }, this.framerate); - } + setTimeout(function () { + _this.animationStep(); + }, this.framerate); }; return World; }()); -var Controls = /** @class */ (function () { - function Controls() { - } - return Controls; -}()); var Infection = /** @class */ (function () { - //public state : string //public exposure: number + //public icnubation: number function Infection(duration, mortality, reach) { this.duration = duration; this.mortality = mortality; @@ -297,7 +289,8 @@ function randomIntFromInterval(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } function convertArrayLenght(inputArray, length) { - //return inputArray + //return inputArray + length = length - 1; var myNewArray = []; for (var a = 0; a < length; a++) { myNewArray.push(inputArray[Math.floor(a / length * inputArray.length)]); @@ -309,10 +302,28 @@ function convertArrayLenght(inputArray, length) { // let's do it... // var framerate = 30; -var personSize = 3; -var world = new World(700, 700, 0.005, framerate, personSize); // width, height, density, framerate, personSize -var infection = new Infection(40, 0.33, 7); // duration, mortality, reach +var personSize = 6; +var world = new World(700, 700, 10, framerate, personSize); // width, height, density, framerate, personSize +var infection = new Infection(200, 0.3, 12); // duration, mortality, reach var mobility = new Mobility(1, 13); // speed, distance world.infection = infection; world.mobility = mobility; world.init(); +// +// dat.gui +// +var gui = new dat.GUI(); +var slider1 = gui.add(world, 'density').min(1).max(20).step(1); +var slider2 = gui.add(world, 'personSize').min(2).max(10).step(1); +var slider3 = gui.add(world.infection, 'duration').min(50).max(500).step(50); +var slider4 = gui.add(world.infection, 'mortality').min(0).max(1).step(0.1); +var slider5 = gui.add(world.infection, 'reach').min(1).max(20).step(1); +var slider6 = gui.add(world.mobility, 'speed').min(0).max(2).step(0.1); +var slider7 = gui.add(world.mobility, 'distance').min(1).max(50).step(1); +slider1.onChange(function () { world.load(); }); +slider2.onChange(function () { world.load(); }); +slider3.onChange(function () { world.load(); }); +slider4.onChange(function () { world.load(); }); +slider5.onChange(function () { world.load(); }); +slider6.onChange(function () { world.load(); }); +slider7.onChange(function () { world.load(); }); diff --git a/app.ts b/app.ts index b896dc2..3776a63 100644 --- a/app.ts +++ b/app.ts @@ -1,10 +1,12 @@ +//import * as dat from 'dat.gui' +//import Chart from 'chart.js' // // classes // class World { public width: number public height: number - public denisty: number + public density: number public infection: Infection public mobility: Mobility public framerate: number @@ -13,27 +15,24 @@ class World { private persons: any private graphData: any = [] private first: number = 0 + private animationRuns = false public chart: Chart - constructor(width: number, height: number, denisty: number, framerate: number, personSize: number) { + constructor(width: number, height: number, density: number, framerate: number, personSize: number) { this.width = width this.height = height - this.denisty = denisty - this.personCount = Math.round(width * height * denisty) + this.density = density this.persons = [] this.framerate = 1000 / framerate this.personSize = personSize } init() { - let body = document.getElementsByTagName("body")[0] + let body = document.getElementById("container") let canvasChart: any = document.createElement('canvas') canvasChart.id = "chart" canvasChart.width = 700 canvasChart.height = 700 - canvasChart.style.zIndex = "2" - canvasChart.style.position = "absolute" canvasChart.style.border = "1px solid" - canvasChart.style.marginLeft = this.width + "px" body.appendChild(canvasChart) this.chart = new Chart(canvasChart, { type: 'line', @@ -100,33 +99,30 @@ class World { canvas.id = "canvas" canvas.width = this.width canvas.height = this.height - canvas.style.zIndex = "1" - canvas.style.position = "absolute" canvas.style.border = "1px solid" body.appendChild(canvas) - let div = document.createElement('div') - div.id = "info" - body.appendChild(div) - document.getElementById("info").innerHTML = "persons: " + this.personCount + this.load() + } + load() { + this.first = 0 + this.persons = [] + this.graphData = [] + this.personCount = this.width * this.height * 0.0001 * this.density for (let a: number = 0; a < this.personCount; a++) { let person = new Person(randomIntFromInterval(0, this.width), randomIntFromInterval(0, this.height), this.width, this.height, this.infection, this.mobility, "uninfected", this.personSize) this.persons.push(person) } - this.animationStep() + if (!this.animationRuns) { + this.animationStep() + this.animationRuns = true + } } animationStep() { - let runAnimation = false - this.first++; - if (this.first==2) - { + this.first++ + if (this.first == 2) { this.persons[0].state = "infected" } // - if (this.first<3) - { - runAnimation = true - } - // let uninfected = 0 let infected = 0 let deceased = 0 @@ -138,7 +134,6 @@ class World { for (let a: number = 0; a < this.persons.length; a++) { for (let b: number = 0; b < this.persons.length; b++) { if (this.persons[a].state == "infected") { - runAnimation = true let dist = Math.sqrt(Math.pow((this.persons[a].xPosition - this.persons[b].xPosition), 2) + Math.pow((this.persons[a].yPosition - this.persons[b].yPosition), 2)) if (dist < this.persons[a].infection.reach + this.persons[a].size) { if (this.persons[b].state == "uninfected") { @@ -160,8 +155,9 @@ class World { recovered++ } } - this.graphData.push({ "uninfected": uninfected, "infected": infected, "deceased": deceased, "recovered": recovered }) - + if (this.first > 2 && infected > 0) { + this.graphData.push({ "uninfected": uninfected, "infected": infected, "deceased": deceased, "recovered": recovered }) + } //convert data let labels = [] let uninfectedArray = [] @@ -175,7 +171,7 @@ class World { deceasedArray.push(this.graphData[a].deceased) recoveredArray.push(this.graphData[a].recovered) } - let xaxisstep = 15; + let xaxisstep = 20 labels = convertArrayLenght(labels, xaxisstep) uninfectedArray = convertArrayLenght(uninfectedArray, xaxisstep) infectedArray = convertArrayLenght(infectedArray, xaxisstep) @@ -194,23 +190,19 @@ class World { this.persons[a].move() this.persons[a].draw(ctx) } - if (runAnimation) { - setTimeout(() => { - this.animationStep() - }, this.framerate) - } - } -} -class Controls { + setTimeout(() => { + this.animationStep() + }, this.framerate) + + } } class Infection { public duration: number public mortality: number public reach: number - - //public state : string //public exposure: number + //public icnubation: number constructor(duration: number, mortality: number, reach: number) { this.duration = duration @@ -329,7 +321,8 @@ function randomIntFromInterval(min: number, max: number) { // min and max includ function convertArrayLenght(inputArray: any, length: number): any { - //return inputArray + //return inputArray + length = length - 1 let myNewArray: any = [] for (let a = 0; a < length; a++) { myNewArray.push(inputArray[Math.floor(a / length * inputArray.length)]) @@ -341,10 +334,28 @@ function convertArrayLenght(inputArray: any, length: number): any { // let's do it... // let framerate: number = 30 -let personSize: number = 3; -let world = new World(700, 700, 0.005, framerate, personSize) // width, height, density, framerate, personSize -let infection = new Infection(40, 0.33, 7) // duration, mortality, reach +let personSize: number = 6 +let world = new World(700, 700, 10, framerate, personSize) // width, height, density, framerate, personSize +let infection = new Infection(200, 0.3, 12) // duration, mortality, reach let mobility = new Mobility(1, 13) // speed, distance world.infection = infection world.mobility = mobility -world.init() \ No newline at end of file +world.init() +// +// dat.gui +// +let gui = new dat.GUI() +let slider1 = gui.add(world, 'density').min(1).max(20).step(1) +let slider2 = gui.add(world, 'personSize').min(2).max(10).step(1) +let slider3 = gui.add(world.infection, 'duration').min(50).max(500).step(50) +let slider4 = gui.add(world.infection, 'mortality').min(0).max(1).step(0.1) +let slider5 = gui.add(world.infection, 'reach').min(1).max(20).step(1) +let slider6 = gui.add(world.mobility, 'speed').min(0).max(2).step(0.1) +let slider7 = gui.add(world.mobility, 'distance').min(1).max(50).step(1) +slider1.onChange(function () { world.load() }) +slider2.onChange(function () { world.load() }) +slider3.onChange(function () { world.load() }) +slider4.onChange(function () { world.load() }) +slider5.onChange(function () { world.load() }) +slider6.onChange(function () { world.load() }) +slider7.onChange(function () { world.load() }) diff --git a/index.html b/index.html index 51e1e61..9da053c 100644 --- a/index.html +++ b/index.html @@ -4,11 +4,14 @@ Minimalistic infection simulation based on very few variables. + + +
diff --git a/package-lock.json b/package-lock.json index 42643d3..e7d7f98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,11 @@ "moment": "^2.10.2" } }, + "@types/dat.gui": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@types/dat.gui/-/dat.gui-0.7.5.tgz", + "integrity": "sha512-5AqLThlTiuDSOZA7XZFogRj/UdGKn/iIfdFPuh37kY4s7TjTt+YUOlUmcCrY6wAYFFyThtt2z8qZlYcdkhJZ5w==" + }, "chart.js": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz", @@ -58,6 +63,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "dat.gui": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/dat.gui/-/dat.gui-0.7.7.tgz", + "integrity": "sha512-sRl/28gF/XRC5ywC9I4zriATTsQcpSsRG7seXCPnTkK8/EQMIbCu5NPMpICLGxX9ZEUvcXR3ArLYCtgreFoMDw==" + }, "moment": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", diff --git a/package.json b/package.json index e5ebdc4..88b2791 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "homepage": "https://github.com/martijnkunstman/GLU-cc-typescript-oop#readme", "dependencies": { "@types/chart.js": "^2.9.21", + "@types/dat.gui": "^0.7.5", "chart.js": "^2.9.3", + "dat.gui": "^0.7.7", "typescript": "^3.9.5" } } diff --git a/style.css b/style.css index 8b74636..8f81d0c 100644 --- a/style.css +++ b/style.css @@ -1,6 +1,26 @@ html, body { margin: 0; - height: 100%; - overflow: hidden +} +#container{ + display: flex; + justify-content: center; + flex-wrap: wrap; + box-sizing: border-box; +} +#canvas{ + width: 100vmin; + height: 100vmin; + box-sizing: border-box; +} +#chart{ + width: 100vmin; + height: 100vmin; + box-sizing: border-box; +} +.save-row{ + display: none; +} +.close-button{ + display: none; } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 88089ac..eb82443 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "module": "none", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ //"lib": ["es2016","dom","es5"], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ @@ -46,7 +46,7 @@ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ - "types": ["chart.js"], /* Type declaration files to be included in compilation. */ + "types": ["chart.js" ,"dat.gui"], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */