diff --git a/lib/app_component.dart b/lib/app_component.dart
new file mode 100644
index 0000000..e5ece87
--- /dev/null
+++ b/lib/app_component.dart
@@ -0,0 +1,47 @@
+import 'package:angular/angular.dart';
+
+import 'dart:html' as html;
+import 'package:rules_of_living/src/App.dart';
+
+@Component(
+ selector: 'my-app',
+ templateUrl: "app_component.html",
+ directives: [coreDirectives]
+)
+class AppComponent implements OnInit {
+ var name = "World";
+
+ App engine;
+
+ @ViewChild("caCanvas")
+ html.CanvasElement canvas;
+
+ @override
+ void ngOnInit() {
+ canvas.context2D.setFillColorRgb(255, 0, 0);
+ canvas.context2D.fillRect(0, 0, 200, 150);
+ engine = new App(canvas);
+
+ html.window.animationFrame.then(animFrame);
+ }
+
+ void animFrame(num now) {
+ engine.process(now);
+ html.window.animationFrame.then(animFrame);
+ }
+
+ void onStartClicked() {
+ engine.running = !engine.running;
+ }
+
+ void onStepClicked() {
+ engine.running = false;
+ engine.update();
+ }
+
+ void onResetClicked() {
+ engine.reset();
+ }
+
+ void onRandomClicked() {}
+}
diff --git a/lib/app_component.html b/lib/app_component.html
new file mode 100644
index 0000000..366ce7b
--- /dev/null
+++ b/lib/app_component.html
@@ -0,0 +1,20 @@
+
Cellular Automata - The Rules of Life
+
+ Ruleset:
+
+
+
+
+
+
+
+
+
+
+ Speed:
+
\ No newline at end of file
diff --git a/lib/App.dart b/lib/src/App.dart
similarity index 78%
rename from lib/App.dart
rename to lib/src/App.dart
index f77ab15..a571dba 100644
--- a/lib/App.dart
+++ b/lib/src/App.dart
@@ -1,7 +1,6 @@
import 'dart:html' as html;
-import 'package:rules_of_living/Cell.dart';
-import 'package:rules_of_living/Grid.dart';
+import 'package:rules_of_living/src/Grid.dart';
class App {
// Elapsed Time Counter - useful for Safety Timeout
@@ -26,12 +25,11 @@ class App {
App(this.canvas) {
_elapsed.start();
- var runBtn = html.querySelector("#run");
- runBtn.onClick.forEach((html.MouseEvent mouse) {
- running = !running;
- if(running) runBtn.innerHtml = "Stop";
- if(!running) runBtn.innerHtml = "Start";
- });
+ }
+
+ void reset () {
+ grid = new Grid(100, 100);
+ running = false;
}
void process(num now) {
@@ -45,7 +43,7 @@ class App {
print("ERROR STUCK IN UPDATE LOOP");
break;
}
- update();
+ if (running == true) update();
_updateLag -= _MS_PER_STEP;
}
@@ -57,7 +55,7 @@ class App {
void update() {
// print("updating");
- if (running) grid.update();
+ grid.update();
}
diff --git a/lib/Cell.dart b/lib/src/Cell.dart
similarity index 77%
rename from lib/Cell.dart
rename to lib/src/Cell.dart
index d9344ff..5301fb6 100644
--- a/lib/Cell.dart
+++ b/lib/src/Cell.dart
@@ -1,4 +1,4 @@
-import 'package:rules_of_living/Rule.dart';
+import 'package:rules_of_living/src/Rule.dart';
class Cell {
bool state;
@@ -6,11 +6,16 @@ class Cell {
List surviveRules = new List();
List birthRules = new List();
+ /// For determining if render updates are necessary in [Grid].render() function
+ bool dirty = false;
+
Cell([bool state = false]) : this.state = state;
void advanceState() {
this.state = this.nextState;
this.nextState = false;
+
+ this.dirty = true;
}
void update(int neighbors) {
diff --git a/lib/Grid.dart b/lib/src/Grid.dart
similarity index 92%
rename from lib/Grid.dart
rename to lib/src/Grid.dart
index 52e0fea..b0d7e9f 100644
--- a/lib/Grid.dart
+++ b/lib/src/Grid.dart
@@ -1,13 +1,15 @@
import 'dart:html' as html;
-import 'Cell.dart';
-import 'Rule.dart';
+import 'package:rules_of_living/src/Cell.dart';
+import 'package:rules_of_living/src/Rule.dart';
class Grid {
final int w;
final int h;
final List> map;
+ bool _dirty = true;
+
Grid(int w, int h)
: this.w = w,
this.h = h,
@@ -82,6 +84,7 @@ class Grid {
for (int x = 0; x < w; x++) {
// DEFAULTS TO CONWAY GAME OF LIFE RANGE OF ONE
map[y][x].update(getSurroundingNeighbors(x, y, 1));
+ if (!_dirty && map[y][x].dirty) _dirty = true;
}
}
for (int y = 0; y < h; y++) {
@@ -110,6 +113,9 @@ class Grid {
}
void render(html.CanvasElement canvas, [num interp]) {
+ // only renders if any cells changed between renders
+ if (!_dirty) return;
+
html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
int brickW = (canvas.width ~/ map[0].length);
int brickH = (canvas.height ~/ map.length);
@@ -124,5 +130,7 @@ class Grid {
ctx.fillRect(x * brickW, y * brickH, brickW, brickH);
}
}
+
+ _dirty = false;
}
}
diff --git a/lib/Rule.dart b/lib/src/Rule.dart
similarity index 100%
rename from lib/Rule.dart
rename to lib/src/Rule.dart
diff --git a/pubspec.yaml b/pubspec.yaml
index 2fe07bc..9dc2faa 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,10 +7,12 @@ homepage: https://www.martyoehme.org/
environment:
sdk: '>=2.0.0-dev.66.0 <2.0.0'
-#dependencies:
-# path: ^1.4.1
+dependencies:
+ angular: ^5.0.0-beta
dev_dependencies:
+ angular_test: ^2.0.0-beta
build_runner: ^0.9.0
+ build_test: ^0.10.2
build_web_compilers: ^0.4.0
- test: ^1.2.0
+ test: ^1.0.0
diff --git a/test/app_test.dart b/test/app_test.dart
new file mode 100644
index 0000000..3e0614e
--- /dev/null
+++ b/test/app_test.dart
@@ -0,0 +1,32 @@
+@TestOn('browser')
+
+import 'package:rules_of_living/app_component.dart';
+import 'package:rules_of_living/app_component.template.dart' as ng;
+import 'package:angular_test/angular_test.dart';
+import 'package:test/test.dart';
+
+void main() {
+ final testBed =
+ NgTestBed.forComponent(ng.AppComponentNgFactory);
+ NgTestFixture fixture;
+
+ setUp(() async {
+ fixture = await testBed.create();
+ });
+
+ tearDown(disposeAnyRunningTest);
+
+ test('Default greeting', () {
+ expect(fixture.text, 'Hello Angular');
+ });
+
+ test('Greet world', () async {
+ await fixture.update((c) => c.name = 'World');
+ expect(fixture.text, 'Hello World');
+ });
+
+ test('Greet world HTML', () {
+ final html = fixture.rootElement.innerHtml;
+ expect(html, 'Hello Angular
');
+ });
+}
diff --git a/web/favicon.png b/web/favicon.png
new file mode 100644
index 0000000..dd18702
Binary files /dev/null and b/web/favicon.png differ
diff --git a/web/index.html b/web/index.html
index 6b86c2d..35bd3cb 100644
--- a/web/index.html
+++ b/web/index.html
@@ -1,29 +1,31 @@
-
+
-
-
-
-
- rules_of_living
-
-
-
+
+
+ Hello Angular
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ Loading...
+
diff --git a/web/main.dart b/web/main.dart
index 8d236aa..3415d86 100644
--- a/web/main.dart
+++ b/web/main.dart
@@ -1,19 +1,7 @@
-import 'dart:html' as html;
+import 'package:angular/angular.dart';
+import 'package:rules_of_living/app_component.template.dart' as ng;
-import 'package:rules_of_living/App.dart';
-
-
-html.CanvasElement el;
-App engine;
void main() {
- el = new html.CanvasElement(width: 500, height: 500);
- html.querySelector('#output').append(el);
- engine = new App(el);
- html.window.animationFrame.then(animFrame);
-}
-
-void animFrame(num now) {
- engine.process(now);
- html.window.animationFrame.then(animFrame);
+ runApp(ng.AppComponentNgFactory);
}
diff --git a/web/styles.css b/web/styles.css
index cc035c9..ef7a186 100644
--- a/web/styles.css
+++ b/web/styles.css
@@ -1,14 +1,117 @@
@import url(https://fonts.googleapis.com/css?family=Roboto);
+@import url(https://fonts.googleapis.com/css?family=Material+Icons);
-html, body {
- width: 100%;
- height: 100%;
- margin: 0;
+/* Master Styles */
+h1 {
+ color: #369;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 250%;
+}
+h2, h3 {
+ color: #444;
+ font-family: Arial, Helvetica, sans-serif;
+ font-weight: lighter;
+}
+body {
+ margin: 2em;
+}
+body, input[text], button {
+ color: #888;
+ font-family: Cambria, Georgia;
+}
+a {
+ cursor: pointer;
+ cursor: hand;
+}
+button {
+ font-family: Arial;
+ background-color: #eee;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 4px;
+ cursor: pointer;
+ cursor: hand;
+}
+button:hover {
+ background-color: #cfd8dc;
+}
+button:disabled {
+ background-color: #eee;
+ color: #aaa;
+ cursor: auto;
+}
+label {
+ padding-right: 0.5em;
+}
+/* Navigation link styles */
+nav a {
+ padding: 5px 10px;
+ text-decoration: none;
+ margin-right: 10px;
+ margin-top: 10px;
+ display: inline-block;
+ background-color: #eee;
+ border-radius: 4px;
+}
+nav a:visited, a:link {
+ color: #607D8B;
+}
+nav a:hover {
+ color: #039be5;
+ background-color: #CFD8DC;
+}
+nav a.active {
+ color: #039be5;
+}
+
+/* items class */
+.items {
+ margin: 0 0 2em 0;
+ list-style-type: none;
padding: 0;
- font-family: 'Roboto', sans-serif;
+ width: 24em;
}
-
-#output {
- padding: 20px;
- text-align: center;
+.items li {
+ cursor: pointer;
+ position: relative;
+ left: 0;
+ background-color: #EEE;
+ margin: .5em;
+ padding: .3em 0;
+ height: 1.6em;
+ border-radius: 4px;
+}
+.items li:hover {
+ color: #607D8B;
+ background-color: #DDD;
+ left: .1em;
+}
+.items li.selected {
+ background-color: #CFD8DC;
+ color: white;
+}
+.items li.selected:hover {
+ background-color: #BBD8DC;
+}
+.items .text {
+ position: relative;
+ top: -3px;
+}
+.items .badge {
+ display: inline-block;
+ font-size: small;
+ color: white;
+ padding: 0.8em 0.7em 0 0.7em;
+ background-color: #607D8B;
+ line-height: 1em;
+ position: relative;
+ left: -1px;
+ top: -4px;
+ height: 1.8em;
+ margin-right: .8em;
+ border-radius: 4px 0 0 4px;
+}
+/* everywhere else */
+* {
+ font-family: Arial, Helvetica, sans-serif;
}