mirror of
https://github.com/rastapasta/mapscii.git
synced 2025-06-01 15:57:29 +02:00
Translate to TypeScript (runs with "bun run main.ts")
This commit is contained in:
parent
4fe9a60a0c
commit
98051b62ca
@ -1,11 +1,11 @@
|
|||||||
module.exports = {
|
export default {
|
||||||
"env": {
|
"env": {
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"node": true,
|
"node": true,
|
||||||
"jest": true
|
"jest": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2018
|
"ecmaVersion": 2020
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
|
3
babel.config.json
Normal file
3
babel.config.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": ["@babel/preset-typescript"]
|
||||||
|
}
|
@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
TODO: params parsing and so on
|
TODO: params parsing and so on
|
||||||
#*/
|
#*/
|
||||||
'use strict';
|
import config from './src/config';
|
||||||
const config = require('./src/config');
|
import Mapscii from './src/Mapscii';
|
||||||
const Mapscii = require('./src/Mapscii');
|
import yargs from 'yargs/yargs';
|
||||||
const argv = require('yargs')
|
import { hideBin } from 'yargs/helpers';
|
||||||
|
|
||||||
|
const argv = yargs(hideBin(process.argv))
|
||||||
.option('latitude', {
|
.option('latitude', {
|
||||||
alias: 'lat',
|
alias: 'lat',
|
||||||
description: 'Latitude of initial centre',
|
description: 'Latitude of initial centre',
|
7542
package-lock.json
generated
7542
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"description": "MapSCII is a Braille & ASCII world map renderer for your console, based on OpenStreetMap",
|
"description": "MapSCII is a Braille & ASCII world map renderer for your console, based on OpenStreetMap",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"start": "node main",
|
"start": "node main",
|
||||||
@ -16,7 +17,7 @@
|
|||||||
"mapscii": "./bin/mapscii.sh"
|
"mapscii": "./bin/mapscii.sh"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"map",
|
"map",
|
||||||
@ -42,11 +43,12 @@
|
|||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"term-mouse": "^0.2.2",
|
"term-mouse": "^0.2.2",
|
||||||
"x256": "0.0.2",
|
"x256": "0.0.2",
|
||||||
"yargs": "^15.4.1"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/preset-typescript": "^7.25.7",
|
||||||
"eslint": "^7.8.1",
|
"eslint": "^7.8.1",
|
||||||
"eslint-plugin-jest": "^24.0.0",
|
"eslint-plugin-jest": "^24.0.0",
|
||||||
"jest": "^26.4.2"
|
"jest": "^29.7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,9 @@
|
|||||||
|
|
||||||
Will either be merged into node-drawille or become an own module at some point
|
Will either be merged into node-drawille or become an own module at some point
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import stringWidth from 'string-width';
|
||||||
const stringWidth = require('string-width');
|
import config from './config';
|
||||||
const config = require('./config');
|
import utils from './utils';
|
||||||
const utils = require('./utils');
|
|
||||||
|
|
||||||
const asciiMap = {
|
const asciiMap = {
|
||||||
// '▬': [2+32, 4+64],
|
// '▬': [2+32, 4+64],
|
||||||
@ -30,13 +29,20 @@ const asciiMap = {
|
|||||||
const termReset = '\x1B[39;49m';
|
const termReset = '\x1B[39;49m';
|
||||||
|
|
||||||
class BrailleBuffer {
|
class BrailleBuffer {
|
||||||
constructor(width, height) {
|
private brailleMap: number[][];
|
||||||
|
private pixelBuffer: Buffer;
|
||||||
|
private charBuffer: unknown[] | null;
|
||||||
|
private foregroundBuffer: Buffer;
|
||||||
|
private backgroundBuffer: Buffer;
|
||||||
|
private height: number;
|
||||||
|
private width: number;
|
||||||
|
private globalBackground: string | null;
|
||||||
|
private asciiToBraille: unknown[];
|
||||||
|
|
||||||
|
constructor(width: number, height: number) {
|
||||||
this.brailleMap = [[0x1, 0x8],[0x2, 0x10],[0x4, 0x20],[0x40, 0x80]];
|
this.brailleMap = [[0x1, 0x8],[0x2, 0x10],[0x4, 0x20],[0x40, 0x80]];
|
||||||
|
|
||||||
this.pixelBuffer = null;
|
|
||||||
this.charBuffer = null;
|
this.charBuffer = null;
|
||||||
this.foregroundBuffer = null;
|
|
||||||
this.backgroundBuffer = null;
|
|
||||||
|
|
||||||
this.asciiToBraille = [];
|
this.asciiToBraille = [];
|
||||||
|
|
||||||
@ -61,7 +67,7 @@ class BrailleBuffer {
|
|||||||
this.backgroundBuffer.fill(0);
|
this.backgroundBuffer.fill(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
setGlobalBackground(background) {
|
setGlobalBackground(background: string) {
|
||||||
this.globalBackground = background;
|
this.globalBackground = background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,4 +214,4 @@ class BrailleBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BrailleBuffer;
|
export default BrailleBuffer;
|
@ -10,13 +10,17 @@
|
|||||||
|
|
||||||
Will most likely be turned into a stand alone module at some point
|
Will most likely be turned into a stand alone module at some point
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import bresenham from 'bresenham';
|
||||||
const bresenham = require('bresenham');
|
import earcut from 'earcut';
|
||||||
const earcut = require('earcut');
|
import BrailleBuffer from './BrailleBuffer';
|
||||||
const BrailleBuffer = require('./BrailleBuffer');
|
|
||||||
|
|
||||||
class Canvas {
|
class Canvas {
|
||||||
constructor(width, height) {
|
private buffer: BrailleBuffer;
|
||||||
|
private height: number;
|
||||||
|
private stack: unknown[] = [];
|
||||||
|
private width: number;
|
||||||
|
|
||||||
|
constructor(width: number, height: number) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.buffer = new BrailleBuffer(width, height);
|
this.buffer = new BrailleBuffer(width, height);
|
||||||
@ -30,7 +34,7 @@ class Canvas {
|
|||||||
this.buffer.clear();
|
this.buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
text(text, x, y, color, center = false) {
|
text(text: string, x: number, y: number, color, center = false) {
|
||||||
this.buffer.writeText(text, x, y, color, center);
|
this.buffer.writeText(text, x, y, color, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +59,8 @@ class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
polygon(rings, color) {
|
polygon(rings, color) {
|
||||||
const vertices = [];
|
const vertices: number[] = [];
|
||||||
const holes = [];
|
const holes: number[] = [];
|
||||||
for (const ring of rings) {
|
for (const ring of rings) {
|
||||||
if (vertices.length) {
|
if (vertices.length) {
|
||||||
if (ring.length < 3) continue;
|
if (ring.length < 3) continue;
|
||||||
@ -197,6 +201,4 @@ class Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Canvas.prototype.stack = [];
|
export default Canvas;
|
||||||
|
|
||||||
module.exports = Canvas;
|
|
@ -5,11 +5,12 @@
|
|||||||
Using 2D spatial indexing to avoid overlapping labels and markers
|
Using 2D spatial indexing to avoid overlapping labels and markers
|
||||||
and to find labels underneath a mouse cursor's position
|
and to find labels underneath a mouse cursor's position
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import RBush from 'rbush';
|
||||||
const RBush = require('rbush');
|
import stringWidth from 'string-width';
|
||||||
const stringWidth = require('string-width');
|
|
||||||
|
|
||||||
module.exports = class LabelBuffer {
|
export default class LabelBuffer {
|
||||||
|
private tree: RBush;
|
||||||
|
private margin: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.tree = new RBush();
|
this.tree = new RBush();
|
||||||
@ -20,11 +21,11 @@ module.exports = class LabelBuffer {
|
|||||||
this.tree.clear();
|
this.tree.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
project(x, y) {
|
project(x: number, y: number) {
|
||||||
return [Math.floor(x/2), Math.floor(y/4)];
|
return [Math.floor(x/2), Math.floor(y/4)];
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIfPossible(text, x, y, feature, margin) {
|
writeIfPossible(text: string, x: number, y: number, feature, margin: number) {
|
||||||
margin = margin || this.margin;
|
margin = margin || this.margin;
|
||||||
|
|
||||||
const point = this.project(x, y);
|
const point = this.project(x, y);
|
||||||
@ -38,15 +39,15 @@ module.exports = class LabelBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
featuresAt(x, y) {
|
featuresAt(x: number, y: number) {
|
||||||
this.tree.search({minX: x, maxX: x, minY: y, maxY: y});
|
this.tree.search({minX: x, maxX: x, minY: y, maxY: y});
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasSpace(text, x, y) {
|
_hasSpace(text: string, x: number, y: number) {
|
||||||
return !this.tree.collides(this._calculateArea(text, x, y));
|
return !this.tree.collides(this._calculateArea(text, x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
_calculateArea(text, x, y, margin = 0) {
|
_calculateArea(text: string, x: number, y: number, margin = 0) {
|
||||||
return {
|
return {
|
||||||
minX: x-margin,
|
minX: x-margin,
|
||||||
minY: y-margin/2,
|
minY: y-margin/2,
|
@ -4,17 +4,31 @@
|
|||||||
|
|
||||||
UI and central command center
|
UI and central command center
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import fs from 'fs';
|
||||||
const fs = require('fs');
|
import keypress from 'keypress';
|
||||||
const keypress = require('keypress');
|
import TermMouse from 'term-mouse';
|
||||||
const TermMouse = require('term-mouse');
|
|
||||||
|
|
||||||
const Renderer = require('./Renderer');
|
import type Canvas from './Canvas';
|
||||||
const TileSource = require('./TileSource');
|
import Renderer from './Renderer';
|
||||||
const utils = require('./utils');
|
import TileSource from './TileSource';
|
||||||
let config = require('./config');
|
import utils from './utils';
|
||||||
|
import globalConfig from './config';
|
||||||
|
|
||||||
|
let config = globalConfig;
|
||||||
|
|
||||||
class Mapscii {
|
class Mapscii {
|
||||||
|
private width: number | null;
|
||||||
|
private height: number | null;
|
||||||
|
private canvas: Canvas | null;
|
||||||
|
private mouse: any;
|
||||||
|
private mouseDragging: boolean;
|
||||||
|
private mousePosition: any;
|
||||||
|
private tileSource: TileSource | null;
|
||||||
|
private renderer: Renderer | null;
|
||||||
|
private zoom: number;
|
||||||
|
private minZoom: number | null;
|
||||||
|
private center: any;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.width = null;
|
this.width = null;
|
||||||
this.height = null;
|
this.height = null;
|
||||||
@ -310,4 +324,4 @@ class Mapscii {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Mapscii;
|
export default Mapscii;
|
@ -4,18 +4,37 @@
|
|||||||
|
|
||||||
The Console Vector Tile renderer - bäm!
|
The Console Vector Tile renderer - bäm!
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import x256 from 'x256';
|
||||||
const x256 = require('x256');
|
import simplify from 'simplify-js';
|
||||||
const simplify = require('simplify-js');
|
|
||||||
|
|
||||||
const Canvas = require('./Canvas');
|
import Canvas from './Canvas';
|
||||||
const LabelBuffer = require('./LabelBuffer');
|
import LabelBuffer from './LabelBuffer';
|
||||||
const Styler = require('./Styler');
|
import Styler from './Styler';
|
||||||
const utils = require('./utils');
|
import utils from './utils';
|
||||||
const config = require('./config');
|
import config from './config';
|
||||||
|
import TileSource from './TileSource';
|
||||||
|
|
||||||
class Renderer {
|
class Renderer {
|
||||||
constructor(output, tileSource, style) {
|
private canvas: Canvas | undefined;
|
||||||
|
private height: number;
|
||||||
|
private labelBuffer: LabelBuffer;
|
||||||
|
private output: unknown;
|
||||||
|
private styler: Styler;
|
||||||
|
private tileSource: TileSource;
|
||||||
|
private width: number;
|
||||||
|
private _seen: Record<string, boolean>;
|
||||||
|
|
||||||
|
private terminal = {
|
||||||
|
CLEAR: '\x1B[2J',
|
||||||
|
MOVE: '\x1B[?6h',
|
||||||
|
};
|
||||||
|
|
||||||
|
private isDrawing = false;
|
||||||
|
private lastDrawAt = 0;
|
||||||
|
private tilePadding = 64;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(output, tileSource: TileSource, style) {
|
||||||
this.output = output;
|
this.output = output;
|
||||||
this.tileSource = tileSource;
|
this.tileSource = tileSource;
|
||||||
this.labelBuffer = new LabelBuffer();
|
this.labelBuffer = new LabelBuffer();
|
||||||
@ -23,13 +42,13 @@ class Renderer {
|
|||||||
this.tileSource.useStyler(this.styler);
|
this.tileSource.useStyler(this.styler);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSize(width, height) {
|
setSize(width: number, height: number) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.canvas = new Canvas(width, height);
|
this.canvas = new Canvas(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
async draw(center, zoom) {
|
async draw(center, zoom: number) {
|
||||||
if (this.isDrawing) return Promise.reject();
|
if (this.isDrawing) return Promise.reject();
|
||||||
this.isDrawing = true;
|
this.isDrawing = true;
|
||||||
|
|
||||||
@ -321,15 +340,4 @@ class Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.prototype.terminal = {
|
export default Renderer;
|
||||||
CLEAR: '\x1B[2J',
|
|
||||||
MOVE: '\x1B[?6h',
|
|
||||||
};
|
|
||||||
|
|
||||||
Renderer.prototype.isDrawing = false;
|
|
||||||
Renderer.prototype.lastDrawAt = 0;
|
|
||||||
Renderer.prototype.labelBuffer = null;
|
|
||||||
Renderer.prototype.tileSource = null;
|
|
||||||
Renderer.prototype.tilePadding = 64;
|
|
||||||
|
|
||||||
module.exports = Renderer;
|
|
@ -8,9 +8,12 @@
|
|||||||
Compiles layer filter instructions into a chain of true/false returning
|
Compiles layer filter instructions into a chain of true/false returning
|
||||||
anonymous functions to improve rendering speed compared to realtime parsing.
|
anonymous functions to improve rendering speed compared to realtime parsing.
|
||||||
*/
|
*/
|
||||||
'use strict';
|
|
||||||
|
|
||||||
class Styler {
|
class Styler {
|
||||||
|
public styleById: Record<string, Record<string, unknown>>;
|
||||||
|
public styleByLayer: Record<string, unknown[]>;
|
||||||
|
private styleName: string;
|
||||||
|
|
||||||
constructor(style) {
|
constructor(style) {
|
||||||
this.styleById = {};
|
this.styleById = {};
|
||||||
this.styleByLayer = {};
|
this.styleByLayer = {};
|
||||||
@ -130,4 +133,4 @@ class Styler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Styler;
|
export default Styler;
|
@ -4,18 +4,22 @@
|
|||||||
|
|
||||||
Handling of and access to single VectorTiles
|
Handling of and access to single VectorTiles
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import { VectorTile } from '@mapbox/vector-tile';
|
||||||
const VectorTile = require('@mapbox/vector-tile').VectorTile;
|
import Protobuf from 'pbf';
|
||||||
const Protobuf = require('pbf');
|
import zlib from 'zlib';
|
||||||
const zlib = require('zlib');
|
import RBush from 'rbush';
|
||||||
const RBush = require('rbush');
|
import x256 from 'x256';
|
||||||
const x256 = require('x256');
|
|
||||||
|
|
||||||
const config = require('./config');
|
import config from './config';
|
||||||
const utils = require('./utils');
|
import utils from './utils';
|
||||||
|
import Styler from './Styler';
|
||||||
|
|
||||||
class Tile {
|
class Tile {
|
||||||
constructor(styler) {
|
public layers: any[];
|
||||||
|
private styler: Styler;
|
||||||
|
private tile: VectorTile;
|
||||||
|
|
||||||
|
constructor(styler: Styler) {
|
||||||
this.styler = styler;
|
this.styler = styler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,11 +33,11 @@ class Tile {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadTile(buffer) {
|
private _loadTile(buffer) {
|
||||||
this.tile = new VectorTile(new Protobuf(buffer));
|
this.tile = new VectorTile(new Protobuf(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
_unzipIfNeeded(buffer) {
|
private _unzipIfNeeded(buffer) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (this._isGzipped(buffer)) {
|
if (this._isGzipped(buffer)) {
|
||||||
zlib.gunzip(buffer, (err, data) => {
|
zlib.gunzip(buffer, (err, data) => {
|
||||||
@ -48,11 +52,11 @@ class Tile {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_isGzipped(buffer) {
|
private _isGzipped(buffer) {
|
||||||
return buffer.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0;
|
return buffer.slice(0, 2).indexOf(Buffer.from([0x1f, 0x8b])) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadLayers() {
|
private _loadLayers() {
|
||||||
const layers = {};
|
const layers = {};
|
||||||
const colorCache = {};
|
const colorCache = {};
|
||||||
for (const name in this.tile.layers) {
|
for (const name in this.tile.layers) {
|
||||||
@ -121,7 +125,7 @@ class Tile {
|
|||||||
return this.layers = layers;
|
return this.layers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addBoundaries(deep, data) {
|
private _addBoundaries(deep, data) {
|
||||||
let minX = 2e308;
|
let minX = 2e308;
|
||||||
let maxX = -2e308;
|
let maxX = -2e308;
|
||||||
let minY = 2e308;
|
let minY = 2e308;
|
||||||
@ -140,7 +144,7 @@ class Tile {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
_reduceGeometry(feature, factor) {
|
private _reduceGeometry(feature, factor) {
|
||||||
const results = [];
|
const results = [];
|
||||||
const geometries = feature.loadGeometry();
|
const geometries = feature.loadGeometry();
|
||||||
for (const points of geometries) {
|
for (const points of geometries) {
|
||||||
@ -164,4 +168,4 @@ class Tile {
|
|||||||
|
|
||||||
Tile.prototype.layers = {};
|
Tile.prototype.layers = {};
|
||||||
|
|
||||||
module.exports = Tile;
|
export default Tile;
|
@ -1,12 +1,12 @@
|
|||||||
'use strict';
|
import { describe, expect, test } from 'jest';
|
||||||
const TileSource = require('./TileSource');
|
import TileSource from './TileSource.ts';
|
||||||
|
|
||||||
describe('TileSource', () => {
|
describe('TileSource', () => {
|
||||||
describe('with a HTTP source', () => {
|
describe('with a HTTP source', () => {
|
||||||
test('sets the mode to 3', async () => {
|
test('sets the mode to 3', async () => {
|
||||||
const tileSource = new TileSource();
|
const tileSource = new TileSource();
|
||||||
await tileSource.init('http://mapscii.me/');
|
await tileSource.init('http://mapscii.me/');
|
||||||
expect(tileSource.mode).toBe(3);
|
expect(tileSource.mode).toBe(Mode.HTTP);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -6,32 +6,39 @@
|
|||||||
* remote TileServer
|
* remote TileServer
|
||||||
* local MBTiles and VectorTiles
|
* local MBTiles and VectorTiles
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import fs from 'fs';
|
||||||
const fs = require('fs');
|
import path from 'path';
|
||||||
const path = require('path');
|
import fetch from 'node-fetch';
|
||||||
const fetch = require('node-fetch');
|
import envPaths from 'env-paths';
|
||||||
const envPaths = require('env-paths');
|
|
||||||
const paths = envPaths('mapscii');
|
const paths = envPaths('mapscii');
|
||||||
|
|
||||||
const Tile = require('./Tile');
|
import Tile from './Tile';
|
||||||
const config = require('./config');
|
import config from './config';
|
||||||
|
|
||||||
// https://github.com/mapbox/node-mbtiles has native build dependencies (sqlite3)
|
// https://github.com/mapbox/node-mbtiles has native build dependencies (sqlite3)
|
||||||
// To maximize MapSCII’s compatibility, MBTiles support must be manually added via
|
// To maximize MapSCII’s compatibility, MBTiles support must be manually added via
|
||||||
// $> npm install -g @mapbox/mbtiles
|
// $> npm install -g @mapbox/mbtiles
|
||||||
let MBTiles = null;
|
let MBTiles = null;
|
||||||
try {
|
try {
|
||||||
MBTiles = require('@mapbox/mbtiles');
|
MBTiles = await import('@mapbox/mbtiles');
|
||||||
} catch (err) {void 0;}
|
} catch (err) {void 0;}
|
||||||
|
|
||||||
const modes = {
|
export enum Mode {
|
||||||
MBTiles: 1,
|
MBTiles = 1,
|
||||||
VectorTile: 2,
|
VectorTile = 2,
|
||||||
HTTP: 3,
|
HTTP = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
class TileSource {
|
class TileSource {
|
||||||
init(source) {
|
private source: string;
|
||||||
|
private cache: any;
|
||||||
|
private cacheSize: number;
|
||||||
|
private cached: any;
|
||||||
|
private mode: Mode | null;
|
||||||
|
private mbtiles: any;
|
||||||
|
private styler: any;
|
||||||
|
|
||||||
|
init(source: string) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
|
||||||
this.cache = {};
|
this.cache = {};
|
||||||
@ -47,14 +54,14 @@ class TileSource {
|
|||||||
this._initPersistence();
|
this._initPersistence();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mode = modes.HTTP;
|
this.mode = Mode.HTTP;
|
||||||
|
|
||||||
} else if (this.source.endsWith('.mbtiles')) {
|
} else if (this.source.endsWith('.mbtiles')) {
|
||||||
if (!MBTiles) {
|
if (!MBTiles) {
|
||||||
throw new Error('MBTiles support must be installed with following command: \'npm install -g @mapbox/mbtiles\'');
|
throw new Error('MBTiles support must be installed with following command: \'npm install -g @mapbox/mbtiles\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mode = modes.MBTiles;
|
this.mode = Mode.MBTiles;
|
||||||
this.loadMBTiles(source);
|
this.loadMBTiles(source);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('source type isn\'t supported yet');
|
throw new Error('source type isn\'t supported yet');
|
||||||
@ -77,7 +84,7 @@ class TileSource {
|
|||||||
this.styler = styler;
|
this.styler = styler;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTile(z, x, y) {
|
getTile(z: number, x: number, y: number) {
|
||||||
if (!this.mode) {
|
if (!this.mode) {
|
||||||
throw new Error('no TileSource defined');
|
throw new Error('no TileSource defined');
|
||||||
}
|
}
|
||||||
@ -95,14 +102,14 @@ class TileSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (this.mode) {
|
switch (this.mode) {
|
||||||
case modes.MBTiles:
|
case Mode.MBTiles:
|
||||||
return this._getMBTile(z, x, y);
|
return this._getMBTile(z, x, y);
|
||||||
case modes.HTTP:
|
case Mode.HTTP:
|
||||||
return this._getHTTP(z, x, y);
|
return this._getHTTP(z, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getHTTP(z, x, y) {
|
private _getHTTP(z: number, x: number, y: number) {
|
||||||
let promise;
|
let promise;
|
||||||
const persistedTile = this._getPersited(z, x, y);
|
const persistedTile = this._getPersited(z, x, y);
|
||||||
if (config.persistDownloadedTiles && persistedTile) {
|
if (config.persistDownloadedTiles && persistedTile) {
|
||||||
@ -122,7 +129,7 @@ class TileSource {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_getMBTile(z, x, y) {
|
private _getMBTile(z: number, x: number, y: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.mbtiles.getTile(z, x, y, (err, buffer) => {
|
this.mbtiles.getTile(z, x, y, (err, buffer) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -133,7 +140,7 @@ class TileSource {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_createTile(z, x, y, buffer) {
|
private _createTile(z: number, x: number, y: number, buffer) {
|
||||||
const name = [z, x, y].join('-');
|
const name = [z, x, y].join('-');
|
||||||
this.cached.push(name);
|
this.cached.push(name);
|
||||||
|
|
||||||
@ -141,7 +148,7 @@ class TileSource {
|
|||||||
return tile.load(buffer);
|
return tile.load(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_initPersistence() {
|
private _initPersistence() {
|
||||||
try {
|
try {
|
||||||
this._createFolder(paths.cache);
|
this._createFolder(paths.cache);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -149,14 +156,14 @@ class TileSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_persistTile(z, x, y, buffer) {
|
private _persistTile(z, x, y, buffer) {
|
||||||
const zoom = z.toString();
|
const zoom = z.toString();
|
||||||
this._createFolder(path.join(paths.cache, zoom));
|
this._createFolder(path.join(paths.cache, zoom));
|
||||||
const filePath = path.join(paths.cache, zoom, `${x}-${y}.pbf`);
|
const filePath = path.join(paths.cache, zoom, `${x}-${y}.pbf`);
|
||||||
return fs.writeFile(filePath, buffer, () => null);
|
return fs.writeFile(filePath, buffer, () => null);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getPersited(z, x, y) {
|
private _getPersited(z: number, x: number, y: number) {
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(path.join(paths.cache, z.toString(), `${x}-${y}.pbf`));
|
return fs.readFileSync(path.join(paths.cache, z.toString(), `${x}-${y}.pbf`));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -164,7 +171,7 @@ class TileSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_createFolder(path) {
|
private _createFolder(path: string): true {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(path);
|
fs.mkdirSync(path);
|
||||||
return true;
|
return true;
|
||||||
@ -175,4 +182,4 @@ class TileSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TileSource;
|
export default TileSource;
|
@ -1,4 +1,4 @@
|
|||||||
module.exports = {
|
export default {
|
||||||
language: 'en',
|
language: 'en',
|
||||||
|
|
||||||
// TODO: adapt to osm2vectortiles successor openmaptiles v3)
|
// TODO: adapt to osm2vectortiles successor openmaptiles v3)
|
||||||
@ -7,7 +7,7 @@ module.exports = {
|
|||||||
|
|
||||||
//source: __dirname+"/../mbtiles/regensburg.mbtiles",
|
//source: __dirname+"/../mbtiles/regensburg.mbtiles",
|
||||||
|
|
||||||
styleFile: __dirname+'/../styles/dark.json',
|
styleFile: import.meta.dirname+'/../styles/dark.json',
|
||||||
|
|
||||||
initialZoom: null,
|
initialZoom: null,
|
||||||
maxZoom: 18,
|
maxZoom: 18,
|
@ -4,15 +4,14 @@
|
|||||||
|
|
||||||
methods used all around
|
methods used all around
|
||||||
*/
|
*/
|
||||||
'use strict';
|
import config from './config';
|
||||||
const config = require('./config');
|
|
||||||
|
|
||||||
const constants = {
|
const constants = {
|
||||||
RADIUS: 6378137,
|
RADIUS: 6378137,
|
||||||
};
|
};
|
||||||
|
|
||||||
const utils = {
|
const utils = {
|
||||||
clamp: (num, min, max) => {
|
clamp: (num: number, min: number, max: number): number => {
|
||||||
if (num <= min) {
|
if (num <= min) {
|
||||||
return min;
|
return min;
|
||||||
} else if (num >= max) {
|
} else if (num >= max) {
|
||||||
@ -22,20 +21,20 @@ const utils = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
baseZoom: (zoom) => {
|
baseZoom: (zoom: number): number => {
|
||||||
return Math.min(config.tileRange, Math.max(0, Math.floor(zoom)));
|
return Math.min(config.tileRange, Math.max(0, Math.floor(zoom)));
|
||||||
},
|
},
|
||||||
|
|
||||||
tilesizeAtZoom: (zoom) => {
|
tilesizeAtZoom: (zoom: number): number => {
|
||||||
return config.projectSize * Math.pow(2, zoom-utils.baseZoom(zoom));
|
return config.projectSize * Math.pow(2, zoom-utils.baseZoom(zoom));
|
||||||
},
|
},
|
||||||
|
|
||||||
deg2rad: (angle) => {
|
deg2rad: (angle: number): number => {
|
||||||
// (angle / 180) * Math.PI
|
// (angle / 180) * Math.PI
|
||||||
return angle * 0.017453292519943295;
|
return angle * 0.017453292519943295;
|
||||||
},
|
},
|
||||||
|
|
||||||
ll2tile: (lon, lat, zoom) => {
|
ll2tile: (lon: number, lat: number, zoom: number) => {
|
||||||
return {
|
return {
|
||||||
x: (lon+180)/360*Math.pow(2, zoom),
|
x: (lon+180)/360*Math.pow(2, zoom),
|
||||||
y: (1-Math.log(Math.tan(lat*Math.PI/180)+1/Math.cos(lat*Math.PI/180))/Math.PI)/2*Math.pow(2, zoom),
|
y: (1-Math.log(Math.tan(lat*Math.PI/180)+1/Math.cos(lat*Math.PI/180))/Math.PI)/2*Math.pow(2, zoom),
|
||||||
@ -43,7 +42,7 @@ const utils = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
tile2ll: (x, y, zoom) => {
|
tile2ll: (x: number, y: number, zoom: number) => {
|
||||||
const n = Math.PI - 2*Math.PI*y/Math.pow(2, zoom);
|
const n = Math.PI - 2*Math.PI*y/Math.pow(2, zoom);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -52,18 +51,18 @@ const utils = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
metersPerPixel: (zoom, lat = 0) => {
|
metersPerPixel: (zoom: number, lat = 0): number => {
|
||||||
return (Math.cos(lat * Math.PI/180) * 2 * Math.PI * constants.RADIUS) / (256 * Math.pow(2, zoom));
|
return (Math.cos(lat * Math.PI/180) * 2 * Math.PI * constants.RADIUS) / (256 * Math.pow(2, zoom));
|
||||||
},
|
},
|
||||||
|
|
||||||
hex2rgb: (color) => {
|
hex2rgb: (color: any): [r: number, g: number, b: number] => {
|
||||||
if (typeof color !== 'string') return [255, 0, 0];
|
if (typeof color !== 'string') return [255, 0, 0];
|
||||||
|
|
||||||
if (!/^#[a-fA-F0-9]{3,6}$/.test(color)) {
|
if (!/^#[a-fA-F0-9]{3,6}$/.test(color)) {
|
||||||
throw new Error(`${color} isn't a supported hex color`);
|
throw new Error(`${color} isn't a supported hex color`);
|
||||||
}
|
}
|
||||||
|
|
||||||
color = color.substr(1);
|
color = color.substring(1);
|
||||||
const decimal = parseInt(color, 16);
|
const decimal = parseInt(color, 16);
|
||||||
|
|
||||||
if (color.length === 3) {
|
if (color.length === 3) {
|
||||||
@ -76,11 +75,11 @@ const utils = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
digits: (number, digits) => {
|
digits: (number: number, digits: number): number => {
|
||||||
return Math.floor(number*Math.pow(10, digits))/Math.pow(10, digits);
|
return Math.floor(number*Math.pow(10, digits))/Math.pow(10, digits);
|
||||||
},
|
},
|
||||||
|
|
||||||
normalize: (ll) => {
|
normalize: (ll: {lat: number, lon: number}): {lat: number, lon: number} => {
|
||||||
if (ll.lon < -180) ll.lon += 360;
|
if (ll.lon < -180) ll.lon += 360;
|
||||||
if (ll.lon > 180) ll.lon -= 360;
|
if (ll.lon > 180) ll.lon -= 360;
|
||||||
|
|
||||||
@ -90,7 +89,7 @@ const utils = {
|
|||||||
return ll;
|
return ll;
|
||||||
},
|
},
|
||||||
|
|
||||||
population: (val) => {
|
population: (val: number): number => {
|
||||||
let bits = 0;
|
let bits = 0;
|
||||||
while (val > 0) {
|
while (val > 0) {
|
||||||
bits += val & 1;
|
bits += val & 1;
|
||||||
@ -100,4 +99,4 @@ const utils = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = utils;
|
export default utils;
|
Loading…
x
Reference in New Issue
Block a user