--- /dev/null
+function ViewFrame() {
+ // dom stuff
+ const map = document.createElement('canvas'); // the map we see
+ map.className = 'map';
+ map.height = window.innerHeight;
+ map.width = window.innerWidth;
+ document.getElementsByTagName('body')[0].append(map);
+ // this is the map that we actually draw on
+ this.map = map.getContext('2d', {
+ alpha: false
+ });
+ this.map.imageSmoothingEnabled = false;
+
+ // the info box in the corner
+ this.infobox = document.getElementsByClassName('infoboxTable')[0];
+ this.infoboxSlots = new Array();
+
+ // load the metadata!
+ this.chunkScript = document.createElement('script');
+ this.chunkScript.type = 'text/javascript';
+ this.chunkScript.src = 'Metadata.js';
+ document.getElementsByTagName('body')[0].append(this.chunkScript);
+ this.chunkScript.addEventListener('load', () => {
+ ViewFrame.initInfobox(this.infobox, this.infoboxSlots);
+ this.x = ViewFrame.chunks.startCoords[0];
+ this.y = ViewFrame.chunks.startCoords[1];
+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
+ this.render();
+ }, {
+ once: true
+ });
+
+ // Tracks images that have been loaded and are on the map
+ this.loadedChunksByName = new Map();
+ // this is needed because [1, 2] != [1, 2] and thats how we store coords.
+ this.loadedChunksByCoords = new Map();
+ this.availableChunks = null; // the chunks in ./Metadata.js
+ // so that we dont render twice at the same time
+ this.rendering = false;
+
+ this.x = -1;
+ this.y = -1; // can be fractional
+ this.zoom = 32; // pixels wide the images are to be
+ this.updateEdges();
+}
+// prototypes, some less... notable? methods are
+// in ViewFrameUtils.js
+ViewFrame.prototype.reloadChunkList = function () {
+ if (this.chunkScript) {
+ this.chunkScript.remove();
+ delete this.chunkScript;
+ }
+
+ this.chunkScript = document.createElement('script');
+ this.chunkScript.type = 'text/javascript';
+ this.chunkScript.src = 'Metadata.js';
+ document.getElementsByTagName('body')[0].append(this.chunkScript);
+
+ this.chunkScript.addEventListener('load', () => {
+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
+ this.render();
+ });
+};
+
+ViewFrame.prototype.render = function () {
+ if (!this.availableChunks) return;
+ if (this.rendering) clearInterval(ViewFrame.intervalRef);
+ this.rendering = true;
+ this.updateEdges();
+ this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
+ // culling
+ this.loadedChunksByCoords
+ .forEach((chunk, coord) => { // check the bounds
+ if (coord[0] < this.eastChunk &&
+ coord[0] >= this.westChunk &&
+ coord[1] <= this.northChunk &&
+ coord[1] >= this.southChunk) {
+
+ this.place(chunk, coord[0], coord[1]);
+ return;
+ }
+ // its out of range!!!
+ // get 'em boys!!!!!
+ this.loadedChunksByCoords.delete(coord);
+ this.loadedChunksByName.delete(coord.join('_'));
+ chunk.remove();
+ });
+
+ // gathering what we need to load
+ const neededChunks = new Set();
+ for (var x = this.westChunk; x < this.eastChunk; x++) {
+ for (var y = this.southChunk; y < this.northChunk; y++) {
+ const chunKey = [x, y]; // chunk + key = chunKey :)
+ const name = chunKey.join('_');
+ // continue if its not available, or it is loaded
+ if (!this.availableChunks.has(name) ||
+ this.loadedChunksByName.has(name)) continue;
+ neededChunks.add(chunKey);
+ }
+ }
+ // iterating over everything we need to load
+ const it = neededChunks.values();
+ ViewFrame.intervalRef = setInterval(() => {
+ let round = it.next();
+ if (!round.done) {
+ // load
+ const img = new Image(32, 32);
+ const name = round.value.join('_');
+
+ img.src = name + '.png';
+
+ decode(img, loadedImage => {
+ this.place(img, round.value[0], round.value[1]);
+ });
+ this.loadedChunksByName.set(name, img);
+ this.loadedChunksByCoords.set(round.value, img);
+ } else {
+ clearInterval(ViewFrame.intervalRef);
+ this.rendering = false;
+ }
+ }, 4);
+};
+
+ViewFrame.prototype.place = function (img, x, y) {
+ x -= this.x;
+ y -= this.y;
+ x *= this.zoom;
+ y *= this.zoom;
+ x += this.width / 2;
+ y += this.height / 2;
+
+ this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom);
+};
+
+ViewFrame.prototype.updateInfobox = function (chunkName) {
+ const chunkMeta = this.availableChunks.get(chunkName);
+ this.infoboxSlots.forEach((l, k) => {
+ l.innerText = chunkMeta ? chunkMeta[k] : '0';
+ });
+};
\ No newline at end of file