summaryrefslogtreecommitdiffstats
path: root/src/view/MapView.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/MapView.ts')
-rw-r--r--src/view/MapView.ts142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/view/MapView.ts b/src/view/MapView.ts
new file mode 100644
index 0000000..b366d28
--- /dev/null
+++ b/src/view/MapView.ts
@@ -0,0 +1,142 @@
+'use strict';
+
+
+import * as util from '../util';
+import EntityPosition from '../model/EntityPosition';
+import MapData from '../model/MapData';
+
+
+const tileSize = 32;
+
+const body = document.getElementsByTagName('body')[0];
+
+
+function loadImage(url: string): Promise<HTMLImageElement> {
+ return new Promise(function(resolve, reject) {
+ var img = new Image();
+ img.addEventListener('load', () => { resolve(img); });
+ img.addEventListener('error', () => { reject(Error('Failed to load ' + url)); });
+ img.src = url;
+ });
+}
+
+function loadImages(imgs: {[key: string]: string}): Promise<{[key: string]: HTMLImageElement}> {
+ return util.mapPromises(_.mapValues(imgs, loadImage));
+}
+
+function loadTiles(tiles: {[key: string]: {file: string}}): Promise<{[key: string]: HTMLImageElement}> {
+ return loadImages(_.mapValues(tiles, (t) => `resources/sprite/tile/${t.file}.png`));
+}
+
+function loadEntities(entities: EntityPosition[]): Promise<{[key: string]: HTMLImageElement}> {
+ var p: {[key: string]: Promise<HTMLImageElement>} = {};
+
+ entities.forEach(e => {
+ p[e.entity.name] = loadImage(`resources/sprite/entity/${e.entity.name}.png`);
+ });
+
+ return util.mapPromises(p);
+}
+
+
+export default class MapView {
+ redrawPending: boolean = false;
+
+ canvas: HTMLCanvasElement;
+ ctx: CanvasRenderingContext2D;
+
+ tiles: {[key: string]: HTMLImageElement};
+ entitySprites: {[key: string]: HTMLImageElement};
+
+ constructor(private map: MapData, private entities: {[key: string]: EntityPosition}) {
+ this.canvas = document.createElement('canvas');
+ this.canvas.style.position = 'absolute';
+ body.appendChild(this.canvas);
+
+ this.ctx = this.canvas.getContext('2d');
+
+ window.addEventListener('resize', () => this.setSize());
+ this.setSize();
+
+ var tilesReady = loadTiles(map.tiles).then((tiles) => {
+ this.tiles = tiles;
+ });
+
+ var entitiesReady = loadEntities(this.getEntities()).then((entities) => {
+ this.entitySprites = entities;
+ });
+
+ Promise.all([tilesReady, entitiesReady]).then(() => {
+ this.redraw();
+ });
+ }
+
+ getEntities(): EntityPosition[] {
+ return _.valuesIn<EntityPosition>(this.entities);
+ }
+
+ setSize() {
+ var e = document.documentElement;
+ this.canvas.width = window.innerWidth || e.clientWidth || body.clientWidth;
+ this.canvas.height = window.innerHeight || e.clientHeight || body.clientHeight;
+
+ this.redraw()
+ }
+
+ drawTile(x: number, y: number, tile: HTMLImageElement) {
+ if (!tile)
+ return;
+
+ this.ctx.drawImage(tile, x, y);
+ }
+
+ drawEntity(e: EntityPosition) {
+ var sprite = this.entitySprites[e.entity.name];
+ if (!sprite)
+ return;
+
+ this.ctx.drawImage(
+ sprite,
+ e.direction*tileSize, 0,
+ tileSize, tileSize,
+ e.position.x*tileSize, e.position.y*tileSize,
+ tileSize, tileSize
+ );
+ }
+
+ draw() {
+ this.redrawPending = false;
+
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ if (!this.tiles || !this.entitySprites)
+ return;
+
+ this.map.layers.forEach((layer) => {
+ let y = 0;
+
+ layer.forEach((row) => {
+ let x = 0;
+
+ for (let tile in row) {
+ this.drawTile(x, y, this.tiles[row[tile]]);
+ x += tileSize;
+ }
+
+ y += tileSize;
+ });
+ });
+
+ this.getEntities().forEach(e => {
+ this.drawEntity(e);
+ });
+ }
+
+ redraw() {
+ if (this.redrawPending)
+ return;
+
+ this.redrawPending = true;
+ window.requestAnimationFrame(() => this.draw());
+ }
+}