git @ Cat's Eye Technologies Jaccia / b5eec77
Use modern yoob.js (Playfield{HTML,Canvas}View), depict on canvas. Cat's Eye Technologies 10 years ago
6 changed file(s) with 453 addition(s) and 82 deletion(s). Raw diff Collapse all Expand all
2727 #########F#
2828 </textarea>
2929
30 <pre id="output" style="border: 1px solid blue">
31 </pre>
30 <div id="display_container">
31 Depict with:
32 <select id="select_depiction">
33 <option>text</option>
34 <option>canvas</option>
35 </select>
36
37 <pre id="display_text"></pre>
38 <canvas id="display_canvas" width="400" height="250">
39 There would be an HTML5 canvas here, but your browser isn't displaying it.
40 </canvas>
41 </div>
3242
3343 </body>
3444 <script src="yoob/controller.js"></script>
3545 <script src="yoob/playfield.js"></script>
46 <script src="yoob/playfield-html-view.js"></script>
47 <script src="yoob/playfield-canvas-view.js"></script>
3648 <script src="../script/jaccia.js"></script>
3749 <script>
38 var output = document.getElementById('output');
50 var pf;
51
52 // Text view
53 var displayText = document.getElementById('display_text');
54 var htmlView = new yoob.PlayfieldHTMLView().init(pf, displayText);
55 htmlView.render = function(state) {
56 return dumpMapper(state);
57 };
58
59 // Canvas view
60 var displayCanvas = document.getElementById('display_canvas');
61 var colourMap = {
62 'Space': '#ffffff',
63 'Wall': '#000000',
64 'Slime': '#00a000',
65 'Food2': '#ff0000',
66 'Food': '#0000ff'
67 };
68 var canvasView = new yoob.PlayfieldCanvasView().init(pf, displayCanvas);
69 canvasView.drawCell = function(ctx, value, playfieldX, playfieldY,
70 canvasX, canvasY, cellWidth, cellHeight) {
71 ctx.fillStyle = colourMap[value] || '#ffffff';
72 ctx.fillRect(canvasX, canvasY, cellWidth, cellHeight);
73 };
74
75 // "View Manager"
76 var currentView = 'text';
77 var views = {
78 'text': htmlView,
79 'canvas': canvasView
80 };
81 var draw = function() {
82 views[currentView].pf = pf;
83 views[currentView].draw();
84 };
85
86 var selectDepiction = document.getElementById('select_depiction');
87 selectDepiction.onchange = function() {
88 var value = selectDepiction.options[selectDepiction.selectedIndex].value;
89 if (value === 'text') {
90 displayText.style.display = 'block';
91 displayCanvas.style.display = 'none';
92 } else {
93 displayText.style.display = 'none';
94 displayCanvas.style.display = 'block';
95 }
96 currentView = value;
97 draw();
98 };
99
100 // Controller. We don't subclass, we just monkeypatch.
39101 var c = new yoob.Controller();
40 var pf;
41
102
42103 c.load = function(text) {
43104 pf = new yoob.Playfield();
44105 pf.setDefault('Space');
45106 pf.load(0, 0, text, loadMapper);
46 output.innerHTML = pf.dump(dumpMapper);
107 draw();
47108 };
48109
49110 c.step = function() {
51112 newPf.setDefault('Space');
52113 evolve_playfield(pf, newPf);
53114 pf = newPf;
54 output.innerHTML = pf.dump(dumpMapper);
115 draw();
55116 };
56117
57118 c.connect({
62123 'edit': 'edit',
63124 'speed': 'speed',
64125 'source': 'input',
65 'display': 'output'
126 'display': 'display_container'
66127 });
128
67129 c.click_load();
68130 </script>
2323 ##F######
2424 </textarea>
2525
26 <pre id="output" style="border: 1px solid blue">
27 </pre>
26 <div id="display_container">
27 Depict with:
28 <select id="select_depiction">
29 <option>text</option>
30 <option>canvas</option>
31 </select>
32
33 <pre id="display_text"></pre>
34 <canvas id="display_canvas" width="400" height="250">
35 There would be an HTML5 canvas here, but your browser isn't displaying it.
36 </canvas>
37 </div>
2838
2939 </body>
3040 <script src="yoob/controller.js"></script>
3141 <script src="yoob/playfield.js"></script>
42 <script src="yoob/playfield-html-view.js"></script>
43 <script src="yoob/playfield-canvas-view.js"></script>
3244 <script src="../script/jacciata.js"></script>
3345 <script>
34 var output = document.getElementById('output');
46 var pf;
47
48 // Text view
49 var displayText = document.getElementById('display_text');
50 var htmlView = new yoob.PlayfieldHTMLView().init(pf, displayText);
51 htmlView.render = function(state) {
52 return dumpMapper(state);
53 };
54
55 // Canvas view
56 var displayCanvas = document.getElementById('display_canvas');
57 var colourMap = {
58 'Space': '#ffffff',
59 'Wall': '#000000',
60 'Slime': '#00a000',
61 'Solved': '#00ff40',
62 'Finish': '#0000ff',
63 'Start': '#ff0000',
64 'Head': '#a0c0a0',
65 'Body': '#80a080'
66 };
67 var canvasView = new yoob.PlayfieldCanvasView().init(pf, displayCanvas);
68 canvasView.drawCell = function(ctx, value, playfieldX, playfieldY,
69 canvasX, canvasY, cellWidth, cellHeight) {
70 ctx.fillStyle = colourMap[value] || '#ffffff';
71 ctx.fillRect(canvasX, canvasY, cellWidth, cellHeight);
72 };
73
74 // "View Manager"
75 var currentView = 'text';
76 var views = {
77 'text': htmlView,
78 'canvas': canvasView
79 };
80 var draw = function() {
81 views[currentView].pf = pf;
82 views[currentView].draw();
83 };
84
85 var selectDepiction = document.getElementById('select_depiction');
86 selectDepiction.onchange = function() {
87 var value = selectDepiction.options[selectDepiction.selectedIndex].value;
88 if (value === 'text') {
89 displayText.style.display = 'block';
90 displayCanvas.style.display = 'none';
91 } else {
92 displayText.style.display = 'none';
93 displayCanvas.style.display = 'block';
94 }
95 currentView = value;
96 draw();
97 };
98
99 // Controller. We don't subclass, we just monkeypatch.
35100 var c = new yoob.Controller();
36 var pf;
37
101
38102 c.load = function(text) {
39103 pf = new yoob.Playfield();
40104 pf.setDefault('Space');
41105 pf.load(0, 0, text, loadMapper);
42 output.innerHTML = pf.dump(dumpMapper);
106 draw();
43107 };
44108
45109 c.step = function() {
47111 newPf.setDefault('Space');
48112 evolve_playfield(pf, newPf);
49113 pf = newPf;
50 output.innerHTML = pf.dump(dumpMapper);
114 draw();
51115 };
52116
53117 c.connect({
58122 'edit': 'edit',
59123 'speed': 'speed',
60124 'source': 'input',
61 'display': 'output'
125 'display': 'display_container'
62126 });
127
63128 c.click_load();
64129 </script>
00 /*
1 * This file is part of yoob.js version 0.3-PRE
1 * This file is part of yoob.js version 0.3
2 * Available from https://github.com/catseye/yoob.js/
23 * This file is in the public domain. See http://unlicense.org/ for details.
34 */
45 if (window.yoob === undefined) yoob = {};
0 /*
1 * This file is part of yoob.js version 0.5
2 * Available from https://github.com/catseye/yoob.js/
3 * This file is in the public domain. See http://unlicense.org/ for details.
4 */
5 if (window.yoob === undefined) yoob = {};
6
7 /*
8 * A view (in the MVC sense) for depicting a yoob.Playfield (-compatible)
9 * object on an HTML5 <canvas> element (or compatible object).
10 *
11 * TODO: don't necesarily resize canvas each time?
12 * TODO: option to stretch content rendering to fill a fixed-size canvas
13 */
14 yoob.PlayfieldCanvasView = function() {
15 this.pf = undefined;
16 this.canvas = undefined;
17
18 this.init = function(pf, canvas) {
19 this.pf = pf;
20 this.canvas = canvas;
21 this.cursors = [];
22 this.cellWidth = 8;
23 this.cellHeight = 8;
24 return this;
25 };
26
27 /* Chain setters */
28 this.setCursors = function(cursors) {
29 this.cursors = cursors;
30 return this;
31 };
32 this.setCellDimensions = function(cellWidth, cellHeight) {
33 this.cellWidth = cellWidth;
34 this.cellHeight = cellHeight;
35 return this;
36 };
37
38 /*
39 * Override these if you want to draw some portion of the
40 * playfield which is not the whole playfield.
41 * (Not yet implemented)
42 */
43 this.getLowerX = function() {
44 return this.pf.getMinX();
45 };
46 this.getUpperX = function() {
47 return this.pf.getMaxX();
48 };
49 this.getLowerY = function() {
50 return this.pf.getMinY();
51 };
52 this.getUpperY = function() {
53 return this.pf.getMaxY();
54 };
55
56 /*
57 * Returns the number of occupied cells in the x direction.
58 */
59 this.getExtentX = function() {
60 if (this.getLowerX() === undefined || this.getUpperX() === undefined) {
61 return 0;
62 } else {
63 return this.getUpperX() - this.getLowerX() + 1;
64 }
65 };
66
67 /*
68 * Returns the number of occupied cells in the y direction.
69 */
70 this.getExtentY = function() {
71 if (this.getLowerY() === undefined || this.getUpperY() === undefined) {
72 return 0;
73 } else {
74 return this.getUpperY() - this.getLowerY() + 1;
75 }
76 };
77
78 /*
79 * Draws cells of the Playfield in a drawing context.
80 * cellWidth and cellHeight are canvas units of measure.
81 *
82 * The default implementation tries to call a .draw() method on the cell's
83 * value, if one exists, and just renders it as text, in black, if not.
84 *
85 * Override if you wish to draw elements in some other way.
86 */
87 this.drawCell = function(ctx, value, playfieldX, playfieldY,
88 canvasX, canvasY, cellWidth, cellHeight) {
89 if (value.draw !== undefined) {
90 value.draw(ctx, playfieldX, playfieldY, canvasX, canvasY,
91 cellWidth, cellHeight);
92 } else {
93 ctx.fillStyle = "black";
94 ctx.fillText(value.toString(), canvasX, canvasY);
95 }
96 };
97
98 /*
99 * Draws the Playfield in a drawing context.
100 * cellWidth and cellHeight are canvas units of measure for each cell.
101 * offsetX and offsetY are canvas units of measure for the top-left
102 * of the entire playfield.
103 */
104 this.drawContext = function(ctx, offsetX, offsetY, cellWidth, cellHeight) {
105 var self = this;
106 this.pf.foreach(function (x, y, value) {
107 self.drawCell(ctx, value, x, y,
108 offsetX + x * cellWidth, offsetY + y * cellHeight,
109 cellWidth, cellHeight);
110 });
111 };
112
113 /*
114 * Draws the Playfield, and a set of Cursors, on a canvas element.
115 * Resizes the canvas to the needed dimensions.
116 * cellWidth and cellHeight are canvas units of measure for each cell.
117 * Note that this is a holdover from when this method was on Playfield
118 * itself; typically you'd just call draw() instead.
119 */
120 this.drawCanvas = function(canvas, cellWidth, cellHeight, cursors) {
121 var ctx = canvas.getContext('2d');
122
123 var width = this.getExtentX();
124 var height = this.getExtentY();
125
126 if (cellWidth === undefined) {
127 ctx.textBaseline = "top";
128 ctx.font = cellHeight + "px monospace";
129 cellWidth = ctx.measureText("@").width;
130 }
131
132 canvas.width = width * cellWidth;
133 canvas.height = height * cellHeight;
134
135 ctx.clearRect(0, 0, canvas.width, canvas.height);
136
137 ctx.textBaseline = "top";
138 ctx.font = cellHeight + "px monospace";
139
140 var offsetX = this.pf.getMinX() * cellWidth * -1;
141 var offsetY = this.pf.getMinY() * cellHeight * -1;
142
143 if (this.fixedPosition) {
144 offsetX = 0;
145 offsetY = 0;
146 }
147
148 for (var i = 0; i < cursors.length; i++) {
149 cursors[i].drawContext(
150 ctx,
151 offsetX + cursors[i].x * cellWidth,
152 offsetY + cursors[i].y * cellHeight,
153 cellWidth, cellHeight
154 );
155 }
156
157 this.drawContext(ctx, offsetX, offsetY, cellWidth, cellHeight);
158 };
159
160 /*
161 * Render the playfield on the canvas.
162 */
163 this.draw = function() {
164 this.drawCanvas(
165 this.canvas, this.cellWidth, this.cellHeight, this.cursors
166 );
167 };
168
169 };
0 /*
1 * This file is part of yoob.js version 0.5
2 * Available from https://github.com/catseye/yoob.js/
3 * This file is in the public domain. See http://unlicense.org/ for details.
4 */
5 if (window.yoob === undefined) yoob = {};
6
7 /*
8 * A view (in the MVC sense) for depicting a yoob.Playfield (-compatible)
9 * object onto any DOM element that supports innerHTML.
10 *
11 * TODO: this may be incomplete; use at your own risk
12 * TODO: have this and the canvas view inherit from a common ABC?
13 */
14 yoob.PlayfieldHTMLView = function() {
15 this.pf = undefined;
16 this.element = undefined;
17
18 this.init = function(pf, element) {
19 this.pf = pf;
20 this.element = element;
21 return this;
22 };
23
24 /*
25 * Override these if you want to draw some portion of the
26 * playfield which is not the whole playfield.
27 */
28 this.getLowerX = function() {
29 return this.pf.getMinX();
30 };
31 this.getUpperX = function() {
32 return this.pf.getMaxX();
33 };
34 this.getLowerY = function() {
35 return this.pf.getMinY();
36 };
37 this.getUpperY = function() {
38 return this.pf.getMaxY();
39 };
40
41 /*
42 * Returns the number of occupied cells in the x direction.
43 */
44 this.getExtentX = function() {
45 if (this.getLowerX() === undefined || this.getUpperX() === undefined) {
46 return 0;
47 } else {
48 return this.getUpperX() - this.getLowerX() + 1;
49 }
50 };
51
52 /*
53 * Returns the number of occupied cells in the y direction.
54 */
55 this.getExtentY = function() {
56 if (this.getLowerY() === undefined || this.getUpperY() === undefined) {
57 return 0;
58 } else {
59 return this.getUpperY() - this.getLowerY() + 1;
60 }
61 };
62
63 /*
64 * Override to convert Playfield values to HTML.
65 */
66 this.render = function(value) {
67 return value;
68 };
69
70 /*
71 * Render the playfield, as HTML, on the DOM element.
72 */
73 this.draw = function() {
74 var text = "";
75 for (var y = this.getLowerY(); y <= this.getUpperY(); y++) {
76 var row = "";
77 for (var x = this.getLowerX(); x <= this.getUpperX(); x++) {
78 row += this.render(this.pf.get(x, y));
79 }
80 text += row + "\n";
81 }
82 this.element.innerHTML = text;
83 };
84
85 };
00 /*
1 * This file is part of yoob.js version 0.2
1 * This file is part of yoob.js version 0.4
2 * Available from https://github.com/catseye/yoob.js/
23 * This file is in the public domain. See http://unlicense.org/ for details.
34 */
45 if (window.yoob === undefined) yoob = {};
2122 */
2223 this.setDefault = function(v) {
2324 this._default = v;
25 return this;
2426 };
2527
2628 /*
99101 this.minY = undefined;
100102 this.maxX = undefined;
101103 this.maxX = undefined;
104 };
105
106 /*
107 * Scroll a rectangular subrectangle of this Playfield, up.
108 * TODO: support other directions.
109 */
110 this.scrollRectangleY = function(dy, minX, minY, maxX, maxY) {
111 if (dy < 1) {
112 for (var y = minY; y <= (maxY + dy); y++) {
113 for (var x = minX; x <= maxX; x++) {
114 this.put(x, y, this.get(x, y - dy));
115 }
116 }
117 } else { alert("scrollRectangleY(" + dy + ") notImplemented"); }
118 };
119
120 this.clearRectangle = function(minX, minY, maxX, maxY) {
121 // Could also do this with a foreach that checks
122 // each position. Would be faster on sparser playfields.
123 for (var y = minY; y <= maxY; y++) {
124 for (var x = minX; x <= maxX; x++) {
125 this.put(x, y, undefined);
126 }
127 }
102128 };
103129
104130 /*
216242 };
217243
218244 /*
219 * Draws elements of the Playfield in a drawing context.
220 * x and y are canvas coordinates, and width and height
221 * are canvas units of measure.
222 * The default implementation just renders them as text,
223 * in black.
224 * Override if you wish to draw them differently.
225 */
226 this.drawElement = function(ctx, x, y, cellWidth, cellHeight, elem) {
227 ctx.fillStyle = "black";
228 ctx.fillText(elem.toString(), x, y);
229 };
230
231 /*
232 * Draws the Playfield in a drawing context.
233 * cellWidth and cellHeight are canvas units of measure for each cell.
234 */
235 this.drawContext = function(ctx, offsetX, offsetY, cellWidth, cellHeight) {
236 var me = this;
237 this.foreach(function (x, y, elem) {
238 me.drawElement(ctx, offsetX + x * cellWidth, offsetY + y * cellHeight,
239 cellWidth, cellHeight, elem);
240 });
241 };
242
245 * Accessors for the minimum (resp. maximum) x (resp. y) values of
246 * occupied (non-default-valued) cells in this Playfield. If there are
247 * no cells in this Playfield, these will refturn undefined. Note that
248 * these are not guaranteed to be tight bounds; if values in cells
249 * are deleted, these bounds may still be considered to be outside them.
250 */
251 this.getMinX = function() {
252 return this.minX;
253 };
254 this.getMaxX = function() {
255 return this.maxX;
256 };
257 this.getMinY = function() {
258 return this.minY;
259 };
260 this.getMaxY = function() {
261 return this.maxY;
262 };
263
264 /*
265 * Returns the number of occupied cells in the x direction.
266 */
243267 this.getExtentX = function() {
244268 if (this.maxX === undefined || this.minX === undefined) {
245269 return 0;
248272 }
249273 };
250274
275 /*
276 * Returns the number of occupied cells in the y direction.
277 */
251278 this.getExtentY = function() {
252279 if (this.maxY === undefined || this.minY === undefined) {
253280 return 0;
255282 return this.maxY - this.minY + 1;
256283 }
257284 };
258
259 /*
260 * Draws the Playfield, and a set of Cursors, on a canvas element.
261 * Resizes the canvas to the needed dimensions.
262 * cellWidth and cellHeight are canvas units of measure for each cell.
263 */
264 this.drawCanvas = function(canvas, cellWidth, cellHeight, cursors) {
265 var ctx = canvas.getContext('2d');
266
267 var width = this.getExtentX();
268 var height = this.getExtentY();
269
270 if (cellWidth === undefined) {
271 ctx.textBaseline = "top";
272 ctx.font = cellHeight + "px monospace";
273 cellWidth = ctx.measureText("@").width;
274 }
275
276 canvas.width = width * cellWidth;
277 canvas.height = height * cellHeight;
278
279 ctx.clearRect(0, 0, canvas.width, canvas.height);
280
281 ctx.textBaseline = "top";
282 ctx.font = cellHeight + "px monospace";
283
284 var offsetX = this.minX * cellWidth * -1;
285 var offsetY = this.minY * cellHeight * -1;
286
287 for (var i = 0; i < cursors.length; i++) {
288 cursors[i].drawContext(
289 ctx,
290 cursors[i].x * cellWidth, cursors[i].y * cellHeight,
291 cellWidth, cellHeight
292 );
293 }
294
295 this.drawContext(ctx, offsetX, offsetY, cellWidth, cellHeight);
296 };
297
298285 };