diff --git a/package-lock.json b/package-lock.json index 3735184..c048f2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1209,6 +1209,391 @@ "fastq": "^1.6.0" } }, + "@pixi/accessibility": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-5.3.3.tgz", + "integrity": "sha512-wC/enJtw5CrdWnu6l5u3VN9UIZPumNSNXlGez2BULY0osiLTywHJPdHpmXMz2YPXw75GsEBzkEvK4LTtnTp21A==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/app": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/app/-/app-5.3.3.tgz", + "integrity": "sha512-OkO7Kq3N+FPRshVmApuiHKBpobic56VYbLVCMYPy6rjV0hc5ctkchKGFyouJuPt/rHeI6FrqZ0TaON1TShnKiA==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3" + } + }, + "@pixi/constants": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-5.3.3.tgz", + "integrity": "sha512-IybgxzLlEPm7ihp70cLNKc3IPyqkFuW+idk9Zw2St+OayJTw5ctCnLAg9cducwIVHjPYTvN46BYDa+n0KRWZYw==", + "dev": true + }, + "@pixi/core": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/core/-/core-5.3.3.tgz", + "integrity": "sha512-taw50LnzV+TQVMx5HQA2ZJgF9wuhZ6DeoXHW2KkevYB0ekKYnEO2VMMiRDMcmchtyvHclJebzjeHZLGqDtKDgw==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/runner": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/ticker": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/display": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/display/-/display-5.3.3.tgz", + "integrity": "sha512-dPm7Vk2BH9byu6RHBYsI9MtjUU8x1HNm/PIi6lIlxANhTjWnhxwfvmrGE7ZcRLThTenNdDVlZ2ke2XAXP98UgA==", + "dev": true, + "requires": { + "@pixi/math": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/extract": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-5.3.3.tgz", + "integrity": "sha512-CE0GA+tEBPurpaXER2B1aq1sdumKLtCqE/Mms6fYUkIKF9D0Ogw9rqo79QCL9XkLMexa7xVeC3KPPiXW5wrOaA==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/filter-alpha": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-5.3.3.tgz", + "integrity": "sha512-AxyHLnvO892va9raZbMMtMtEGDVqO8SvEHHNnCjTBEZ67kVKy0HEYXFOBA6nJZ6BiTgGp9js+7kevi11tfqnJQ==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3" + } + }, + "@pixi/filter-blur": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-5.3.3.tgz", + "integrity": "sha512-vLN1DL6PQXo4p7j/32PZIf+lhcBVfb9hdphSmtbxlAlpbhMWI52n3YUkeInwHs7Ev08NyhI/UhNWHqjN/lAM3w==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/settings": "5.3.3" + } + }, + "@pixi/filter-color-matrix": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-5.3.3.tgz", + "integrity": "sha512-HFr+vth5ZHHEFJYcjtWZ+O0s7Z2YWJyDyxr+nTd5Q8AT7gMDTVehpNVrm7ByaCKeEovOZzZI6A347+WmHcNpGg==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3" + } + }, + "@pixi/filter-displacement": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-5.3.3.tgz", + "integrity": "sha512-kvrKMgqW4ELg+yT2p5vmu6h/IER/L8GD1PWyXovnzpI8RG7k8l136F9VvA3wkB6sYuNcXiDtqMtRQy5e6O4+rw==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/math": "5.3.3" + } + }, + "@pixi/filter-fxaa": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-5.3.3.tgz", + "integrity": "sha512-p4vKdBwaoGRNZcoHz2ET8hBF1SoWvy9xU2B3Ci32+c0dg89ZUdGTEW0zimUHi2gMdU+2v/T0lqZ9NC9B6WVYAg==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3" + } + }, + "@pixi/filter-noise": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-5.3.3.tgz", + "integrity": "sha512-HCky3XPk6BYGXTS7d9/FnAHnqq7Rwm5Rlj2XtWW3JItXGCScEBII227xYwrJu5Ke84tpVlDXK4W1/BevZ1AwlQ==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3" + } + }, + "@pixi/graphics": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-5.3.3.tgz", + "integrity": "sha512-1bn9Jptg3JXgVOw0SrEMdmjSwkTBYDm6fPnPnh4goF3yDozh0xEqmXobVtCgy2fulMfHRzIfbgtRxrBf2mkCAg==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/interaction": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-5.3.3.tgz", + "integrity": "sha512-Tjuw4XwmrG1fhGzfn5oGspRJT2OtlH+6V7AHscH0v5Ht1Kvk6aKjNncZuSCXllhGGlIuMu3Nn9WPvDEIvW3JNw==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/ticker": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/loaders": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-5.3.3.tgz", + "integrity": "sha512-wj0DzniApfDoZA/buMmO/CgCB7Q7SsESForHh7wSd7UC8rrCmz5prUTEICmJGhdHpBuVB7KDPtwaaLtr9Q/kQg==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/utils": "5.3.3", + "resource-loader": "^3.0.1" + } + }, + "@pixi/math": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/math/-/math-5.3.3.tgz", + "integrity": "sha512-k5C3kQpxlGm2AdBJEUjjW2l2YlSvTKf+54vNOjD4UcEfRoDevC5p4Zg49q3UAu855lrs5qw49AbkrFKsQvPIRA==", + "dev": true + }, + "@pixi/mesh": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-5.3.3.tgz", + "integrity": "sha512-q8w70oAFNdArzOHVnsn7ban68NmO5S5TMg6qSez4A8te6cebMRQsNrT/0dQ/nZcG7ACFK4jiYfbXRQivO+jgVA==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/mesh-extras": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-5.3.3.tgz", + "integrity": "sha512-V2hARC7nUPaTEFxd+B8GDkSMrMZ38S8/IInqtYzGUy6FtFs7IYKty9Rz/G665eN7ThIq8tZrOVZOl6JRBtEC8A==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/mesh": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/mixin-cache-as-bitmap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-5.3.3.tgz", + "integrity": "sha512-P1mo3HKDWS8IZLgaP8gujiy4We4vRcxJH6EvQAevf+GsBzdjKfcGgkKzVb9HlyQvsXML5gpTOJuw5eKgRTxSQA==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/mixin-get-child-by-name": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-5.3.3.tgz", + "integrity": "sha512-CksDZ5ZG4/tHZfDOwSuznANduasJg5JR89X3D6E9DVYx4CLVE3G2K1sbeiOJNXfGIKy30UoSD7Y7IFmUzLxp/g==", + "dev": true, + "requires": { + "@pixi/display": "5.3.3" + } + }, + "@pixi/mixin-get-global-position": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-5.3.3.tgz", + "integrity": "sha512-M3faQYDW/ISa1+lhVkjHXRALJ33BMzLN+7x9ucx8VeCmUWvcaLlRo3CaxZsgiR+52Fii5WHl/PF/cMzdkRMF9g==", + "dev": true, + "requires": { + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3" + } + }, + "@pixi/particles": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/particles/-/particles-5.3.3.tgz", + "integrity": "sha512-t+lG8iGNYyS6ujKvC9qQjKzyxvjxqbFxvB6hkXcOKR98JWM2726ZguHouFlIbOzOxYAGoeuHIWSDlnQNvnVE2g==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/polyfill": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-5.3.3.tgz", + "integrity": "sha512-gmx67A6VmwKllxfIMQWzMUNJ8wJfWPT5FlUR0SoPastdTB/SfbgbyQBgKLZHqgmc6LOh2CrOLhN423lNiAroeA==", + "dev": true, + "requires": { + "es6-promise-polyfill": "^1.2.0", + "object-assign": "^4.1.1" + } + }, + "@pixi/prepare": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-5.3.3.tgz", + "integrity": "sha512-DPsKWfYJ97J67YCjPU6uvU+LBdw+64O9LG9vmzfChmYXom5VMQF9yUC6ZoYTHUPmH31iilqzGeMlPUTobnqSog==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/graphics": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/text": "5.3.3", + "@pixi/ticker": "5.3.3" + } + }, + "@pixi/runner": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-5.3.3.tgz", + "integrity": "sha512-7eLZxxT+PwxuwzcRL1egrnEdLHwD41yFb24pMSo6XM86ppP1tdBjrv5+pLDnUuDEfNjZQxx07FAlZY+sMKANmw==", + "dev": true + }, + "@pixi/settings": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-5.3.3.tgz", + "integrity": "sha512-1MYJokqpPUtvYEX0BVi0Pq2Xi6KGmWDV5hlQnTXY9NGv6tmqrPYvIb/uHFaDyVUWmrqsFL3xZ4W5zMo+c/dwVA==", + "dev": true, + "requires": { + "ismobilejs": "^1.1.0" + } + }, + "@pixi/sprite": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-5.3.3.tgz", + "integrity": "sha512-qo7DG0oWS1uIBqfxw2jZPn34RCR6gQ+IjZRBpFxZPKPB1cL359scZmDBqBbQ4bd4rJ/6QXQfzUdGhXfQJtc9oQ==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/sprite-animated": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-5.3.3.tgz", + "integrity": "sha512-nG5j8veJ/cFXQTgzafPLkZqaHKbuaHcIj+ZYN1I2f31Y85/pfr2PQQLHbGr+3441wOYkEHht9nHhmZHWlOOZ0Q==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/ticker": "5.3.3" + } + }, + "@pixi/sprite-tiling": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-5.3.3.tgz", + "integrity": "sha512-+Xk9AUh82rpArtrnZkw+9aJchrmHZ8QkpjsPRJcgPFHx3WEfABIkT6QEoYbRKiYH34OgO7ZOUXy9hcGPHnxjvw==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/spritesheet": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-5.3.3.tgz", + "integrity": "sha512-pTkOCTL8jsmyAguCgcbz03UPYu+3buRkgua1g/vGyeoZBN2eJ04iSXdB0pfPrsPisxkvThGHyU23UqEDYVtXRQ==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/loaders": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/text": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/text/-/text-5.3.3.tgz", + "integrity": "sha512-juinZC2yFXnzucWWxSdty9nfIIOAq2WA8DD2k40YL+7Y5L52/ggkgnokeQ2lrTb1BvTfx6YVNlvAsKonUek0Og==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/text-bitmap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-5.3.3.tgz", + "integrity": "sha512-QRRdEAFBwmRctp8PCPii5WUPM57T1I3r/EwyTvFCCDubOYOZu4aX/iFpCKZMl5GIphDFaGp8mNvbl+BwjUmBCA==", + "dev": true, + "requires": { + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/loaders": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/mesh": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/text": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, + "@pixi/ticker": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-5.3.3.tgz", + "integrity": "sha512-p5F/dwJGwfZWUg5cCPqOnEx5iYGW+huQlZZtrTKKd1KoVehFsrzHeRBOEp4d584jsOmBf7fjJaUTyzsFn0YtOQ==", + "dev": true, + "requires": { + "@pixi/settings": "5.3.3" + } + }, + "@pixi/utils": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-5.3.3.tgz", + "integrity": "sha512-GDP2h1Mph9Uei4zmJjzDK6GZ5S9O2A09VySVfWyKgWwP3SQ/Ss0bGYm4sE6+u1NMSz1WCrLgu66H82XuXs2Cbg==", + "dev": true, + "requires": { + "@pixi/constants": "5.3.3", + "@pixi/settings": "5.3.3", + "earcut": "^2.1.5", + "eventemitter3": "^3.1.0", + "url": "^0.11.0" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "dev": true + } + } + }, "@soda/friendly-errors-webpack-plugin": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.1.tgz", @@ -5123,6 +5508,12 @@ "stream-shift": "^1.0.0" } }, + "earcut": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.2.tgz", + "integrity": "sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ==", + "dev": true + }, "easy-stack": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", @@ -5310,6 +5701,12 @@ "is-symbol": "^1.0.2" } }, + "es6-promise-polyfill": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es6-promise-polyfill/-/es6-promise-polyfill-1.2.0.tgz", + "integrity": "sha1-84kl8jyz4+jObNqP93T867sJDN4=", + "dev": true + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -7623,6 +8020,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", + "dev": true + }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -7826,6 +8229,12 @@ "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==", "dev": true }, + "leaflet-pixi-overlay": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/leaflet-pixi-overlay/-/leaflet-pixi-overlay-1.8.1.tgz", + "integrity": "sha512-YEAvD5vGuhCvVnlcgMxQyh5wIKDtfRoDXUp/iLd3HNY+mOLhVKMqogQXmyBbzjn4eYkzAOVRF1DBPJaCjYrb8w==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8235,6 +8644,12 @@ } } }, + "mini-signals": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mini-signals/-/mini-signals-1.2.0.tgz", + "integrity": "sha1-RbCAE8X65RokqhqTXNMXye1yHXQ=", + "dev": true + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -8965,6 +9380,12 @@ "lines-and-columns": "^1.1.6" } }, + "parse-uri": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/parse-uri/-/parse-uri-1.0.3.tgz", + "integrity": "sha512-upMnGxNcm+45So85HoguwZTVZI9u11i36DdxJfGF2HYWS2eh3TIx7+/tTi7qrEq15qzGkVhsKjesau+kCk48pA==", + "dev": true + }, "parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", @@ -9103,6 +9524,48 @@ "pinkie": "^2.0.0" } }, + "pixi.js": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-5.3.3.tgz", + "integrity": "sha512-uFQOXXyPMAVVayDebSFBS1AFfPT6QYNuz9Vu11yI2/k1DAef/rbYoJpSMM6SeB6dezDJPtIAaXXNxdaYzbe+kg==", + "dev": true, + "requires": { + "@pixi/accessibility": "5.3.3", + "@pixi/app": "5.3.3", + "@pixi/constants": "5.3.3", + "@pixi/core": "5.3.3", + "@pixi/display": "5.3.3", + "@pixi/extract": "5.3.3", + "@pixi/filter-alpha": "5.3.3", + "@pixi/filter-blur": "5.3.3", + "@pixi/filter-color-matrix": "5.3.3", + "@pixi/filter-displacement": "5.3.3", + "@pixi/filter-fxaa": "5.3.3", + "@pixi/filter-noise": "5.3.3", + "@pixi/graphics": "5.3.3", + "@pixi/interaction": "5.3.3", + "@pixi/loaders": "5.3.3", + "@pixi/math": "5.3.3", + "@pixi/mesh": "5.3.3", + "@pixi/mesh-extras": "5.3.3", + "@pixi/mixin-cache-as-bitmap": "5.3.3", + "@pixi/mixin-get-child-by-name": "5.3.3", + "@pixi/mixin-get-global-position": "5.3.3", + "@pixi/particles": "5.3.3", + "@pixi/polyfill": "5.3.3", + "@pixi/prepare": "5.3.3", + "@pixi/runner": "5.3.3", + "@pixi/settings": "5.3.3", + "@pixi/sprite": "5.3.3", + "@pixi/sprite-animated": "5.3.3", + "@pixi/sprite-tiling": "5.3.3", + "@pixi/spritesheet": "5.3.3", + "@pixi/text": "5.3.3", + "@pixi/text-bitmap": "5.3.3", + "@pixi/ticker": "5.3.3", + "@pixi/utils": "5.3.3" + } + }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -10258,6 +10721,16 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "resource-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/resource-loader/-/resource-loader-3.0.1.tgz", + "integrity": "sha512-fBuCRbEHdLCI1eglzQhUv9Rrdcmqkydr1r6uHE2cYHvRBrcLXeSmbE/qI/urFt8rPr/IGxir3BUwM5kUK8XoyA==", + "dev": true, + "requires": { + "mini-signals": "^1.2.0", + "parse-uri": "^1.0.0" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", diff --git a/package.json b/package.json index 4edb8e2..40d52dc 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "scripts": { - "serve": "vue-cli-service serve", - "build": "vue-cli-service build", + "serve": "vue-cli-service serve ", + "build": "vue-cli-service build --modern --report", "lint": "vue-cli-service lint" }, "dependencies": { @@ -27,7 +27,9 @@ "eslint": "^7.5.0", "eslint-plugin-vue": "^7.0.0-0", "leaflet": "^1.7.1", + "leaflet-pixi-overlay": "^1.8.1", "normalize-scss": "^7.0.1", + "pixi.js": "^5.3.3", "sass": "^1.29.0", "sass-loader": "^10.1.0", "typescript": "~3.9.3", diff --git a/public/images/armor.png b/public/images/armor.png new file mode 100644 index 0000000..0044af1 Binary files /dev/null and b/public/images/armor.png differ diff --git a/public/images/armor_depleted.png b/public/images/armor_depleted.png new file mode 100644 index 0000000..c9bdc24 Binary files /dev/null and b/public/images/armor_depleted.png differ diff --git a/public/images/blank.png b/public/images/blank.png new file mode 100644 index 0000000..e0d1092 Binary files /dev/null and b/public/images/blank.png differ diff --git a/public/images/block_nether_flat.png b/public/images/block_nether_flat.png new file mode 100644 index 0000000..298cdf9 Binary files /dev/null and b/public/images/block_nether_flat.png differ diff --git a/public/images/block_nether_surface.png b/public/images/block_nether_surface.png new file mode 100644 index 0000000..d6d1a51 Binary files /dev/null and b/public/images/block_nether_surface.png differ diff --git a/public/images/block_other.png b/public/images/block_other.png new file mode 100644 index 0000000..6756844 Binary files /dev/null and b/public/images/block_other.png differ diff --git a/public/images/block_skylands.png b/public/images/block_skylands.png new file mode 100644 index 0000000..641155f Binary files /dev/null and b/public/images/block_skylands.png differ diff --git a/public/images/block_the_end_flat.png b/public/images/block_the_end_flat.png new file mode 100644 index 0000000..574d213 Binary files /dev/null and b/public/images/block_the_end_flat.png differ diff --git a/public/images/block_the_end_surface.png b/public/images/block_the_end_surface.png new file mode 100644 index 0000000..69bcc32 Binary files /dev/null and b/public/images/block_the_end_surface.png differ diff --git a/public/images/block_world_biome.png b/public/images/block_world_biome.png new file mode 100644 index 0000000..a72932a Binary files /dev/null and b/public/images/block_world_biome.png differ diff --git a/public/images/block_world_cave.png b/public/images/block_world_cave.png new file mode 100644 index 0000000..b6a547b Binary files /dev/null and b/public/images/block_world_cave.png differ diff --git a/public/images/block_world_flat.png b/public/images/block_world_flat.png new file mode 100644 index 0000000..1a511bd Binary files /dev/null and b/public/images/block_world_flat.png differ diff --git a/public/images/block_world_surface.png b/public/images/block_world_surface.png new file mode 100644 index 0000000..603c6d5 Binary files /dev/null and b/public/images/block_world_surface.png differ diff --git a/public/images/book.png b/public/images/book.png new file mode 100644 index 0000000..727dcda Binary files /dev/null and b/public/images/book.png differ diff --git a/public/images/cave_off.png b/public/images/cave_off.png new file mode 100644 index 0000000..500d987 Binary files /dev/null and b/public/images/cave_off.png differ diff --git a/public/images/cave_on.png b/public/images/cave_on.png new file mode 100644 index 0000000..0639576 Binary files /dev/null and b/public/images/cave_on.png differ diff --git a/public/images/chat_bubble.png b/public/images/chat_bubble.png new file mode 100644 index 0000000..51e11a4 Binary files /dev/null and b/public/images/chat_bubble.png differ diff --git a/public/images/chat_cursor.png b/public/images/chat_cursor.png new file mode 100644 index 0000000..e3d38ab Binary files /dev/null and b/public/images/chat_cursor.png differ diff --git a/public/images/clock_day.png b/public/images/clock_day.png new file mode 100644 index 0000000..6ed0dae Binary files /dev/null and b/public/images/clock_day.png differ diff --git a/public/images/clock_night.png b/public/images/clock_night.png new file mode 100644 index 0000000..0832f0c Binary files /dev/null and b/public/images/clock_night.png differ diff --git a/public/images/compass.png b/public/images/compass.png new file mode 100644 index 0000000..2614dd3 Binary files /dev/null and b/public/images/compass.png differ diff --git a/public/images/compass_E.png b/public/images/compass_E.png new file mode 100644 index 0000000..a12f987 Binary files /dev/null and b/public/images/compass_E.png differ diff --git a/public/images/compass_N.png b/public/images/compass_N.png new file mode 100644 index 0000000..4794e36 Binary files /dev/null and b/public/images/compass_N.png differ diff --git a/public/images/compass_NE.png b/public/images/compass_NE.png new file mode 100644 index 0000000..e4c6574 Binary files /dev/null and b/public/images/compass_NE.png differ diff --git a/public/images/compass_NW.png b/public/images/compass_NW.png new file mode 100644 index 0000000..b657abf Binary files /dev/null and b/public/images/compass_NW.png differ diff --git a/public/images/compass_SW.png b/public/images/compass_SW.png new file mode 100644 index 0000000..f85c0d3 Binary files /dev/null and b/public/images/compass_SW.png differ diff --git a/public/images/compass_W.png b/public/images/compass_W.png new file mode 100644 index 0000000..a90055f Binary files /dev/null and b/public/images/compass_W.png differ diff --git a/public/images/compass_alt.png b/public/images/compass_alt.png new file mode 100644 index 0000000..0e7cc4b Binary files /dev/null and b/public/images/compass_alt.png differ diff --git a/public/images/compass_flat.png b/public/images/compass_flat.png new file mode 100644 index 0000000..3a81604 Binary files /dev/null and b/public/images/compass_flat.png differ diff --git a/public/images/dynmap.ico b/public/images/dynmap.ico new file mode 100644 index 0000000..035da52 Binary files /dev/null and b/public/images/dynmap.ico differ diff --git a/public/images/follow_off.png b/public/images/follow_off.png new file mode 100644 index 0000000..ba506d0 Binary files /dev/null and b/public/images/follow_off.png differ diff --git a/public/images/follow_on.png b/public/images/follow_on.png new file mode 100644 index 0000000..2fb7be7 Binary files /dev/null and b/public/images/follow_on.png differ diff --git a/public/images/heart.png b/public/images/heart.png new file mode 100644 index 0000000..fba8477 Binary files /dev/null and b/public/images/heart.png differ diff --git a/public/images/heart_depleted.png b/public/images/heart_depleted.png new file mode 100644 index 0000000..c8aef57 Binary files /dev/null and b/public/images/heart_depleted.png differ diff --git a/public/images/home.png b/public/images/home.png new file mode 100644 index 0000000..5b15f03 Binary files /dev/null and b/public/images/home.png differ diff --git a/src/assets/css/images/link.png b/public/images/link.png similarity index 100% rename from src/assets/css/images/link.png rename to public/images/link.png diff --git a/public/images/list_off.png b/public/images/list_off.png new file mode 100644 index 0000000..b7be11b Binary files /dev/null and b/public/images/list_off.png differ diff --git a/public/images/list_on.png b/public/images/list_on.png new file mode 100644 index 0000000..285f76e Binary files /dev/null and b/public/images/list_on.png differ diff --git a/public/images/moon.png b/public/images/moon.png new file mode 100644 index 0000000..0283a87 Binary files /dev/null and b/public/images/moon.png differ diff --git a/public/images/player.png b/public/images/player.png new file mode 100644 index 0000000..212039f Binary files /dev/null and b/public/images/player.png differ diff --git a/public/images/player_death.png b/public/images/player_death.png new file mode 100644 index 0000000..9abd211 Binary files /dev/null and b/public/images/player_death.png differ diff --git a/public/images/player_face.png b/public/images/player_face.png new file mode 100644 index 0000000..206c6f3 Binary files /dev/null and b/public/images/player_face.png differ diff --git a/public/images/player_follow_off.png b/public/images/player_follow_off.png new file mode 100644 index 0000000..935e7c6 Binary files /dev/null and b/public/images/player_follow_off.png differ diff --git a/public/images/player_follow_on.gif b/public/images/player_follow_on.gif new file mode 100644 index 0000000..6937e81 Binary files /dev/null and b/public/images/player_follow_on.gif differ diff --git a/public/images/player_follow_on.png b/public/images/player_follow_on.png new file mode 100644 index 0000000..fa790c5 Binary files /dev/null and b/public/images/player_follow_on.png differ diff --git a/public/images/player_travel.png b/public/images/player_travel.png new file mode 100644 index 0000000..03ea756 Binary files /dev/null and b/public/images/player_travel.png differ diff --git a/public/images/scrolldown.png b/public/images/scrolldown.png new file mode 100644 index 0000000..9d07aa6 Binary files /dev/null and b/public/images/scrolldown.png differ diff --git a/public/images/scrollup.png b/public/images/scrollup.png new file mode 100644 index 0000000..b6b6c0c Binary files /dev/null and b/public/images/scrollup.png differ diff --git a/public/images/server.png b/public/images/server.png new file mode 100644 index 0000000..e28417c Binary files /dev/null and b/public/images/server.png differ diff --git a/public/images/sidebar_hint.png b/public/images/sidebar_hint.png new file mode 100644 index 0000000..15e2b7d Binary files /dev/null and b/public/images/sidebar_hint.png differ diff --git a/public/images/sign.png b/public/images/sign.png new file mode 100644 index 0000000..8d8573c Binary files /dev/null and b/public/images/sign.png differ diff --git a/public/images/sign_home.png b/public/images/sign_home.png new file mode 100644 index 0000000..5ecfcec Binary files /dev/null and b/public/images/sign_home.png differ diff --git a/public/images/sign_sign.png b/public/images/sign_sign.png new file mode 100644 index 0000000..5eae09b Binary files /dev/null and b/public/images/sign_sign.png differ diff --git a/public/images/sign_sign_alt.png b/public/images/sign_sign_alt.png new file mode 100644 index 0000000..9834150 Binary files /dev/null and b/public/images/sign_sign_alt.png differ diff --git a/public/images/sign_warp.png b/public/images/sign_warp.png new file mode 100644 index 0000000..9f05e51 Binary files /dev/null and b/public/images/sign_warp.png differ diff --git a/public/images/spawn.png b/public/images/spawn.png new file mode 100644 index 0000000..177650b Binary files /dev/null and b/public/images/spawn.png differ diff --git a/public/images/sun.png b/public/images/sun.png new file mode 100644 index 0000000..40e3962 Binary files /dev/null and b/public/images/sun.png differ diff --git a/public/images/warp.png b/public/images/warp.png new file mode 100644 index 0000000..8ed89e7 Binary files /dev/null and b/public/images/warp.png differ diff --git a/public/images/weather_stormy.png b/public/images/weather_stormy.png new file mode 100644 index 0000000..45808fb Binary files /dev/null and b/public/images/weather_stormy.png differ diff --git a/public/images/weather_stormy_day.png b/public/images/weather_stormy_day.png new file mode 100644 index 0000000..dea2320 Binary files /dev/null and b/public/images/weather_stormy_day.png differ diff --git a/public/images/weather_stormy_night.png b/public/images/weather_stormy_night.png new file mode 100644 index 0000000..fe08ba8 Binary files /dev/null and b/public/images/weather_stormy_night.png differ diff --git a/public/images/weather_sunny.png b/public/images/weather_sunny.png new file mode 100644 index 0000000..8ef8cbd Binary files /dev/null and b/public/images/weather_sunny.png differ diff --git a/public/images/weather_sunny_day.png b/public/images/weather_sunny_day.png new file mode 100644 index 0000000..94ce5b0 Binary files /dev/null and b/public/images/weather_sunny_day.png differ diff --git a/public/images/weather_sunny_night.png b/public/images/weather_sunny_night.png new file mode 100644 index 0000000..fe4fd8b Binary files /dev/null and b/public/images/weather_sunny_night.png differ diff --git a/public/images/weather_thunder.png b/public/images/weather_thunder.png new file mode 100644 index 0000000..07bbfc0 Binary files /dev/null and b/public/images/weather_thunder.png differ diff --git a/public/images/weather_thunder_day.png b/public/images/weather_thunder_day.png new file mode 100644 index 0000000..8900521 Binary files /dev/null and b/public/images/weather_thunder_day.png differ diff --git a/public/images/weather_thunder_night.png b/public/images/weather_thunder_night.png new file mode 100644 index 0000000..63b359e Binary files /dev/null and b/public/images/weather_thunder_night.png differ diff --git a/public/images/window_close.png b/public/images/window_close.png new file mode 100644 index 0000000..586de30 Binary files /dev/null and b/public/images/window_close.png differ diff --git a/public/images/window_close_hover.png b/public/images/window_close_hover.png new file mode 100644 index 0000000..08656f6 Binary files /dev/null and b/public/images/window_close_hover.png differ diff --git a/public/images/window_open.png b/public/images/window_open.png new file mode 100644 index 0000000..f84684c Binary files /dev/null and b/public/images/window_open.png differ diff --git a/public/images/window_pinned.png b/public/images/window_pinned.png new file mode 100644 index 0000000..9051e4f Binary files /dev/null and b/public/images/window_pinned.png differ diff --git a/public/images/window_pinned_hover.png b/public/images/window_pinned_hover.png new file mode 100644 index 0000000..e1f963d Binary files /dev/null and b/public/images/window_pinned_hover.png differ diff --git a/public/images/window_unpinned.png b/public/images/window_unpinned.png new file mode 100644 index 0000000..f84684c Binary files /dev/null and b/public/images/window_unpinned.png differ diff --git a/public/images/zoom_in.png b/public/images/zoom_in.png new file mode 100644 index 0000000..8b91d8d Binary files /dev/null and b/public/images/zoom_in.png differ diff --git a/public/images/zoom_out.png b/public/images/zoom_out.png new file mode 100644 index 0000000..9af74b2 Binary files /dev/null and b/public/images/zoom_out.png differ diff --git a/public/index.html b/public/index.html index 0e40cc6..79357ee 100644 --- a/public/index.html +++ b/public/index.html @@ -14,13 +14,87 @@ + +
+ + + + + + +
+ diff --git a/src/App.vue b/src/App.vue index 1c4de4d..4b8c3ce 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,11 +1,11 @@ - - \ No newline at end of file diff --git a/src/components/Map.vue b/src/components/Map.vue new file mode 100644 index 0000000..ce8462c --- /dev/null +++ b/src/components/Map.vue @@ -0,0 +1,195 @@ + + + + + \ No newline at end of file diff --git a/src/components/PlayerListItem.vue b/src/components/PlayerListItem.vue deleted file mode 100644 index a7bbfcd..0000000 --- a/src/components/PlayerListItem.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 3f72479..2d2e53e 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -1,30 +1,112 @@ - \ No newline at end of file diff --git a/src/components/map/control/ClockControl.vue b/src/components/map/control/ClockControl.vue new file mode 100644 index 0000000..4628de6 --- /dev/null +++ b/src/components/map/control/ClockControl.vue @@ -0,0 +1,56 @@ + + + \ No newline at end of file diff --git a/src/components/map/control/CoordinatesControl.vue b/src/components/map/control/CoordinatesControl.vue new file mode 100644 index 0000000..e72804c --- /dev/null +++ b/src/components/map/control/CoordinatesControl.vue @@ -0,0 +1,43 @@ + + + \ No newline at end of file diff --git a/src/components/map/control/LinkControl.vue b/src/components/map/control/LinkControl.vue new file mode 100644 index 0000000..700d747 --- /dev/null +++ b/src/components/map/control/LinkControl.vue @@ -0,0 +1,40 @@ + + + \ No newline at end of file diff --git a/src/components/map/control/LogoControl.vue b/src/components/map/control/LogoControl.vue new file mode 100644 index 0000000..c1322c8 --- /dev/null +++ b/src/components/map/control/LogoControl.vue @@ -0,0 +1,42 @@ + + + \ No newline at end of file diff --git a/src/components/map/layer/MapLayer.vue b/src/components/map/layer/MapLayer.vue index ef11b66..71f7cf1 100644 --- a/src/components/map/layer/MapLayer.vue +++ b/src/components/map/layer/MapLayer.vue @@ -3,7 +3,8 @@ import {defineComponent} from "@vue/runtime-core"; import {DynmapMap} from "@/dynmap"; import L from 'leaflet'; import {useStore} from "@/store"; -import {hdMapType} from "@/leaflet/mapType/HDMapType"; +import {HDMapType} from "@/leaflet/mapType/HDMapType"; +import {MutationTypes} from "@/store/mutation-types"; export default defineComponent({ props: { @@ -21,15 +22,11 @@ export default defineComponent({ } }, - data() { + setup() { + let layer = undefined as HDMapType | undefined; + return { - layer: hdMapType({ - maxZoom: this.map.nativeZoomLevels + this.map.extraZoomLevels, - maxNativeZoom: this.map.nativeZoomLevels, - errorTileUrl: 'images/blank.png', - worldName: this.map.world, - prefix: this.map.prefix, - }) as L.Layer, + layer, } }, @@ -41,7 +38,7 @@ export default defineComponent({ watch: { active(newValue) { - console.warn(`Active for ${this.map.world} ${this.map.name} now ${newValue}`); + console.warn(`Active for ${this.map.world.name} ${this.map.name} now ${newValue}`); if(newValue) { this.enableLayer(); @@ -52,7 +49,13 @@ export default defineComponent({ }, mounted() { - console.log('mounted ' + this.name + ' ' + this.active); + // console.log('mounted ' + this.name + ' ' + this.active); + this.layer = new HDMapType({ + errorTileUrl: 'images/blank.png', + mapSettings: Object.freeze(JSON.parse(JSON.stringify(this.map))), + }) as HDMapType; + + console.log(this.layer); if(this.active) { this.enableLayer(); @@ -60,7 +63,8 @@ export default defineComponent({ }, unmounted() { - console.log('unmounted ' + this.name); + // console.log('unmounted ' + this.name); + this.disableLayer(); }, render() { @@ -69,12 +73,24 @@ export default defineComponent({ methods: { enableLayer() { - console.warn('Enabling layer ' + this.map.world + ' ' + this.map.name); + if(!this.layer) { + return; + } + + console.warn('Enabling layer ' + this.map.world.name + ' ' + this.map.name); + + useStore().commit(MutationTypes.SET_CURRENT_PROJECTION, this.layer.getProjection()); this.leaflet.addLayer(this.layer); + this.leaflet.panTo(this.layer.getProjection().locationToLatLng(this.map.world.center), { + noMoveStart: true, + animate: false, + }); }, disableLayer() { - console.warn('Disabling layer ' + this.map.world + ' ' + this.map.name); - this.layer.remove(); + if(this.layer) { + console.warn('Disabling layer ' + this.map.world.name + ' ' + this.map.name); + this.layer.remove(); + } } } }) diff --git a/src/components/map/layer/MarkerSetLayer.vue b/src/components/map/layer/MarkerSetLayer.vue new file mode 100644 index 0000000..beb2505 --- /dev/null +++ b/src/components/map/layer/MarkerSetLayer.vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/src/components/map/layer/PlayersLayer.vue b/src/components/map/layer/PlayersLayer.vue index 9beab9e..599f917 100644 --- a/src/components/map/layer/PlayersLayer.vue +++ b/src/components/map/layer/PlayersLayer.vue @@ -1,33 +1,49 @@ + + \ No newline at end of file diff --git a/src/components/map/marker/PlayerMarker.vue b/src/components/map/marker/PlayerMarker.vue index 0db7c1c..cb0fa5e 100644 --- a/src/components/map/marker/PlayerMarker.vue +++ b/src/components/map/marker/PlayerMarker.vue @@ -1,29 +1,108 @@ diff --git a/src/components/map/vector/Areas.vue b/src/components/map/vector/Areas.vue new file mode 100644 index 0000000..694d90c --- /dev/null +++ b/src/components/map/vector/Areas.vue @@ -0,0 +1,237 @@ + + + \ No newline at end of file diff --git a/src/components/map/vector/Circle.vue b/src/components/map/vector/Circle.vue new file mode 100644 index 0000000..d37c55d --- /dev/null +++ b/src/components/map/vector/Circle.vue @@ -0,0 +1,81 @@ + + + \ No newline at end of file diff --git a/src/components/sidebar/FollowTarget.vue b/src/components/sidebar/FollowTarget.vue new file mode 100644 index 0000000..98680c3 --- /dev/null +++ b/src/components/sidebar/FollowTarget.vue @@ -0,0 +1,65 @@ + + + + + \ No newline at end of file diff --git a/src/components/PlayerList.vue b/src/components/sidebar/PlayerList.vue similarity index 67% rename from src/components/PlayerList.vue rename to src/components/sidebar/PlayerList.vue index e9fb0e5..67b33ca 100644 --- a/src/components/PlayerList.vue +++ b/src/components/sidebar/PlayerList.vue @@ -1,12 +1,10 @@ + + \ No newline at end of file diff --git a/src/components/WorldList.vue b/src/components/sidebar/WorldList.vue similarity index 66% rename from src/components/WorldList.vue rename to src/components/sidebar/WorldList.vue index 7c1328b..2f24f8e 100644 --- a/src/components/WorldList.vue +++ b/src/components/sidebar/WorldList.vue @@ -1,12 +1,10 @@ - \ No newline at end of file diff --git a/src/dynmap.d.ts b/src/dynmap.d.ts index a9ba9c5..8fc9ab0 100644 --- a/src/dynmap.d.ts +++ b/src/dynmap.d.ts @@ -1,8 +1,12 @@ -import {LatLng} from "leaflet"; +import {CircleMarkerOptions, PathOptions, PointTuple, PolylineOptions} from "leaflet"; +import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl"; +import {LogoControlOptions} from "@/leaflet/control/LogoControl"; +import {ClockControlOptions} from "@/leaflet/control/ClockControl"; declare global { interface Window { - config: DynmapConfig + config: DynmapConfig; + hideSplash: Function; } } @@ -27,9 +31,9 @@ interface DynmapServerConfig { chatInterval: number; defaultMap?: string; defaultWorld?: string; - defaultZoom?: number; + defaultZoom: number; followMap?: string; - followZoom?: number; + followZoom: number; updateInterval: number; showLayerControl: boolean; title: string; @@ -52,7 +56,16 @@ interface DynmapMessageConfig { } interface DynmapComponentConfig { + markers: DynmapMarkersConfig; playerMarkers?: DynmapPlayerMarkersConfig; + coordinatesControl?: CoordinatesControlOptions; + clockControl ?: ClockControlOptions; + linkControl: boolean; + logoControls: Array; +} + +interface DynmapMarkersConfig { + showLabels: boolean } interface DynmapPlayerMarkersConfig { @@ -72,7 +85,7 @@ interface DynmapWorld { title: string; height: number; center: Coordinate; - maps: Array; + maps: Map; } interface DynmapMap { @@ -95,6 +108,12 @@ interface DynmapMap { extraZoomLevels: number; } +interface DynmapWorldState { + raining: boolean; + thundering: boolean; + timeOfDay: number; +} + interface Coordinate { x: number; y: number; @@ -116,12 +135,10 @@ interface DynmapConfigurationResponse { } interface DynmapUpdateResponse { + worldState: DynmapWorldState; configHash: number; playerCount: number; - raining: boolean; - thundering: boolean; - timeOfDay: number; - players: Array; + players: Set; timestamp: number; //TODO: Tiles etc } @@ -135,4 +152,61 @@ interface DynmapPlayer { location: DynmapLocation; } +interface DynmapMarkerSet { + label: string; + hidden: boolean; + priority: number; + minZoom?: number; + maxZoom?: number; + showLabels?: boolean; + markers: Map; + areas: Map; + lines: Map; + circles: Map; +} +interface DynmapMarker { + dimensions: PointTuple; + icon: string; + label: string; + isHTML: boolean; + location: Coordinate; + minZoom?: number; + maxZoom?: number; + popupContent?: string; +} + +interface DynmapArea { + style: PolylineOptions; + label: string; + isHTML: boolean; + x: Array; + y: PointTuple; + z: Array; + minZoom?: number; + maxZoom?: number; + popupContent?: string; +} + +interface DynmapLine { + x: Array; + y: Array; + z: Array; + style: PolylineOptions; + label: string; + isHTML: boolean; + minZoom?: number; + maxZoom?: number; + popupContent?: string; +} + +interface DynmapCircle { + location: Coordinate; + radius: PointTuple; + style: CircleMarkerOptions; + label: string; + isHTML: boolean; + minZoom?: number; + maxZoom?: number; + popupContent?: string; +} diff --git a/src/leaflet/control/ClockControl.ts b/src/leaflet/control/ClockControl.ts new file mode 100644 index 0000000..3211658 --- /dev/null +++ b/src/leaflet/control/ClockControl.ts @@ -0,0 +1,123 @@ +import L, {ControlOptions} from 'leaflet'; +import {useStore} from "@/store"; +import {DynmapWorldState} from "@/dynmap"; + +export interface ClockControlOptions extends ControlOptions { + showDigitalClock: boolean; + showWeather: boolean; +} + +export class ClockControl extends L.Control { + // @ts-ignore + options: ClockControlOptions; + + private _map ?: L.Map; + private _container?: HTMLElement; + private _sun?: HTMLElement; + private _moon?: HTMLElement; + private _clock?: HTMLElement; + private _weather?: HTMLElement; + + constructor(options: ClockControlOptions) { + super(options); + + options.position = 'topleft'; + L.Util.setOptions(this, options); + } + + onAdd(map: L.Map) { + this._container = L.DomUtil.create('div', 'largeclock timeofday'); + this._sun = L.DomUtil.create('div', 'timeofday sun', this._container); + this._moon = L.DomUtil.create('div', 'timeofday moon', this._sun); + + this._sun.style.backgroundPosition = (-150) + 'px ' + (-150) + 'px'; + this._moon.style.backgroundPosition = (-150) + 'px ' + (-150) + 'px'; + + if (this.options.showDigitalClock) { + this._clock = L.DomUtil.create('div', 'timeofday digitalclock', this._container) + } + + if (this.options.showWeather) { + this._weather = L.DomUtil.create('div', 'weather', this._container) + } + + return this._container; + } + + update(worldState: DynmapWorldState) { + const timeOfDay = worldState.timeOfDay; + let sunAngle; + + if (timeOfDay > 23100 || timeOfDay < 12900) { + //day mode + let movedTime = timeOfDay + 900; + movedTime = (movedTime >= 24000) ? movedTime - 24000 : movedTime; + //Now we have 0 -> 13800 for the day period + //Divide by 13800*2=27600 instead of 24000 to compress day + sunAngle = ((movedTime) / 27600 * 2 * Math.PI); + } else { + //night mode + const movedTime = timeOfDay - 12900; + //Now we have 0 -> 10200 for the night period + //Divide by 10200*2=20400 instead of 24000 to expand night + sunAngle = Math.PI + ((movedTime) / 20400 * 2 * Math.PI); + } + + const moonAngle = sunAngle + Math.PI; + + if (timeOfDay >= 0) { + this._sun!.style.backgroundPosition = (-50 * Math.cos(sunAngle)) + 'px ' + (-50 * Math.sin(sunAngle)) + 'px'; + this._moon!.style.backgroundPosition = (-50 * Math.cos(moonAngle)) + 'px ' + (-50 * Math.sin(moonAngle)) + 'px'; + } else { + this._sun!.style.backgroundPosition = '-150px -150px'; + this._moon!.style.backgroundPosition = '-150px -150px'; + } + + const minecraftTime = this.getMinecraftTime(timeOfDay); + + if(timeOfDay >= 0) { + this._clock!.classList.remove(minecraftTime.night ? 'day' : 'night'); + this._clock!.classList.add(minecraftTime.day ? 'day' : 'night'); + this._clock!.textContent = [ + minecraftTime.hours.toString().padStart(2, '0'), + minecraftTime.minutes.toString().padStart(2, '0') + ].join(':'); + } else { + this._clock!.classList.remove(minecraftTime.night ? 'day' : 'night'); + this._clock!.textContent = ''; + } + + if(this.options.showWeather) { + const dayNight = (timeOfDay > 23100 || timeOfDay < 12900) ? "day" : "night"; + let className = 'sunny'; + + if (worldState.raining) { + className = 'stormy'; + + if (worldState.thundering) { + className = 'thunder'; + } + } + + this._weather?.classList.remove('stormy_day', 'stormy_night', 'sunny_day', 'sunny_night', 'thunder_day', 'thunder_night'); + this._weather?.classList.add(`${className}_${dayNight}`); + } + } + + getMinecraftTime(serverTime: number) { + const day = serverTime >= 0 && serverTime < 13700; + + return { + serverTime: serverTime, + days: Math.floor((serverTime + 8000) / 24000), + + // Assuming it is day at 6:00 + hours: (Math.floor(serverTime / 1000) + 6) % 24, + minutes: Math.floor(((serverTime / 1000) % 1) * 60), + seconds: Math.floor(((((serverTime / 1000) % 1) * 60) % 1) * 60), + + day: day, + night: !day + }; + } +} \ No newline at end of file diff --git a/src/leaflet/control/CoordinatesControl.js b/src/leaflet/control/CoordinatesControl.js deleted file mode 100644 index e3bdc98..0000000 --- a/src/leaflet/control/CoordinatesControl.js +++ /dev/null @@ -1,108 +0,0 @@ -import L from 'leaflet'; - -L.Control.CoordinatesControl = L.Control.extend({ - options: { - showY: true, - showRegion: false, - showChunk: false, - label: 'x,y,z: ', - position: 'topleft', - }, - - _coordsContainer: undefined, - _regionContainer: undefined, - _chunkContainer: undefined, - - constructor(options) { - L.Util.setOptions(this, options); - }, - - onAdd(map) { - var container = L.DomUtil.create('div', 'coord-control'); - - if (!this.options.showY) { - container.classList.add('coord-control-noy'); - } - - this._coordsContainer = L.DomUtil.create('span', 'coord-control-value'); - this._coordsContainer.innerText = this.options.showY ? '---,---,---' : '---,---'; - this._coordsContainer.dataset.label = this.options.label; - container.insertAdjacentElement('beforeend', this._coordsContainer); - - if (this.options.showRegion) { - this._regionContainer = L.DomUtil.create('span', 'coord-control-value'); - this._regionContainer.innerText = '--------'; - container.insertAdjacentElement('beforeend', this._regionContainer); - } - - if (this.options.showChunk) { - this._chunkContainer = L.DomUtil.create('span', 'coord-control-value'); - this._chunkContainer.innerText = '---,---'; - this._chunkContainer.dataset.label = 'Chunk: '; - container.insertAdjacentElement('beforeend', this._chunkContainer); - } - - map.on('mousemove', this._onMouseMove, this); - map.on('mouseout', this._onMouseOut, this); - - this._update(); - return container; - }, - - remove() { - if (!this._map) { - return this; - } - - this._map.on('mousemove', this._onMouseMove, this); - this._map.on('mouseout', this._onMouseOut, this); - L.Control.prototype.remove.call(this); - - return this; - }, - - _onMouseMove(event) { - if (!this._map) { - return; - } - - var loc = dynmap.getProjection().fromLatLngToLocation(event.latlng, dynmap.world.sealevel + 1); - - if (this.options.showY) { - this._coordsContainer.innerText = Math.round(loc.x) + ',' + loc.y + ',' + Math.round(loc.z); - } else { - this._coordsContainer.innerText = Math.round(loc.x) + ',' + Math.round(loc.z); - } - - if (this.options.showRegion) { - this._regionContainer.innerText = 'r.' + Math.floor(loc.x / 512) + '.' + Math.floor(loc.z / 512) + '.mca'; - } - - if (this.options.showChunk) { - this._chunkContainer.innerText = 'Chunk: ' + Math.floor(loc.x / 16) + ',' + Math.floor(loc.z / 16); - } - }, - - _onMouseOut() { - if (!this._map) { - return; - } - - if (this.options.showY) { - this._coordsContainer.innerText = '---,---'; - } else { - this._coordsContainer.innerText = '---,---,---'; - } - - if (this.options.showRegion) { - this._regionContainer.innerText = '--------'; - } - - if (this.options.showChunk) { - this._chunkContainer.innerText = '---,---'; - } - }, - - _update() { - } -}); diff --git a/src/leaflet/control/CoordinatesControl.ts b/src/leaflet/control/CoordinatesControl.ts new file mode 100644 index 0000000..aec6a14 --- /dev/null +++ b/src/leaflet/control/CoordinatesControl.ts @@ -0,0 +1,148 @@ +import L, {ControlOptions, LeafletMouseEvent} from 'leaflet'; +import {useStore} from "@/store"; +import {Coordinate} from "@/dynmap"; + +const store = useStore(); + +export interface CoordinatesControlOptions extends ControlOptions { + showY: boolean; + showRegion: boolean; + showChunk: boolean; + label: string; +} + +export class CoordinatesControl extends L.Control { + // @ts-ignore + options: CoordinatesControlOptions; + + private _map ?: L.Map; + private _location?: Coordinate; + private _locationChanged: boolean = false; + private readonly _coordsContainer: HTMLSpanElement; + private readonly _regionContainer: HTMLSpanElement; + private readonly _chunkContainer: HTMLSpanElement; + + constructor(options: CoordinatesControlOptions) { + super(options); + + options.showRegion = true; + options.showChunk = true; + this._coordsContainer = L.DomUtil.create('span', 'value coordinates'); + this._chunkContainer = L.DomUtil.create('span', 'value chunk'); + this._regionContainer = L.DomUtil.create('span', 'value region'); + + options.position = 'bottomleft'; + L.Util.setOptions(this, options); + } + + onAdd(map: L.Map) { + const container = L.DomUtil.create('div', 'leaflet-control-coordinates'); + + this._coordsContainer.textContent = this.options.showY ? '-----, ----- , -----' : '-----, -----'; + this._coordsContainer.dataset.label = this.options.label; + container.appendChild(this._coordsContainer); + + if (this.options.showRegion) { + this._regionContainer.textContent = '--------------'; + this._regionContainer.dataset.label = 'Region'; + container.appendChild(this._regionContainer); + } + + if (this.options.showChunk) { + this._chunkContainer.textContent = '----, ----'; + this._chunkContainer.dataset.label = 'Chunk'; + container.appendChild(this._chunkContainer); + } + + map.on('mousemove', this._onMouseMove, this); + map.on('mouseout', this._onMouseOut, this); + + return container; + } + + remove() { + if (!this._map) { + return this; + } + + this._map.on('mousemove', this._onMouseMove, this); + this._map.on('mouseout', this._onMouseOut, this); + L.Control.prototype.remove.call(this); + + return this; + } + + _onMouseMove(event: LeafletMouseEvent) { + if (!this._map || !store.state.currentWorld) { + return; + } + + this._location = store.state.currentProjection.latLngToLocation(event.latlng, store.state.currentWorld.seaLevel + 1); + + if(!this._locationChanged) { + this._locationChanged = true; + requestAnimationFrame(() => this._update()); + } + } + + _onMouseOut() { + if (!this._map) { + return; + } + + this._location = undefined; + + if(!this._locationChanged) { + this._locationChanged = true; + requestAnimationFrame(() => this._update()); + } + } + + _update() { + if (!this._map || !store.state.currentWorld || !this._locationChanged) { + return; + } + + this._locationChanged = false; + + if(!this._location) { + if (this.options.showY) { + this._coordsContainer.textContent = '-----, ----- , -----'; + } else { + this._coordsContainer.textContent = '-----, -----'; + } + + if (this.options.showRegion) { + this._regionContainer.textContent = '--------------'; + } + + if (this.options.showChunk) { + this._chunkContainer.textContent = '----, ----'; + } + + return; + } + + const x = Math.round(this._location.x).toString().padStart(5, ' '), + y = this._location.y.toString().padStart(3, ' '), + z = Math.round(this._location.z).toString().padStart(5, ' '), + regionX = Math.floor(this._location.x / 512).toString().padStart(3, ' '), + regionZ = Math.floor(this._location.z / 512).toString().padStart(3, ' '), + chunkX = Math.floor(this._location.x / 16).toString().padStart(4, ' '), + chunkZ = Math.floor(this._location.z / 16).toString().padStart(4, ' '); + + if (this.options.showY) { + this._coordsContainer.textContent = `${x}, ${y}, ${z}`; + } else { + this._coordsContainer.textContent = `${x}, ${z}`; + } + + if (this.options.showRegion) { + this._regionContainer.textContent = `r.${regionX}, ${regionZ}.mca`; + } + + if (this.options.showChunk) { + this._chunkContainer.textContent = `${chunkX}, ${chunkZ}`; + } + } +} diff --git a/src/leaflet/control/LayerControl.ts b/src/leaflet/control/LayerControl.ts new file mode 100644 index 0000000..f996de5 --- /dev/null +++ b/src/leaflet/control/LayerControl.ts @@ -0,0 +1,78 @@ +import L, {ControlOptions, ControlPosition, LeafletMouseEvent} from 'leaflet'; +import {useStore} from "@/store"; + +const store = useStore(); + +export interface CoordinatesControlOptions extends ControlOptions { + showY: boolean; + showRegion: boolean; + showChunk: boolean; + label: string; +} + +export class LayerControl extends L.Control.Layers { + constructor() { + super(); + } + + // Function override to include pos + addOverlay(layer: L.Layer, name: string, pos: number) { + this._addLayer(layer, name, true, pos); + this._update(); + return this; + } + + // Function override to order layers by pos + _addLayer(layer: L.Layer, name: string, overlay, pos: number) { + var id = L.stamp(layer); + + this._layers[pos] = { + layer: layer, + name: name, + overlay: overlay, + id: id + }; + + if (this.options.autoZIndex && layer.setZIndex) { + this._lastZIndex++; + layer.setZIndex(this._lastZIndex); + } + } + + // Function override to convert the position-based ordering into the id-based ordering + _onInputClick() { + var i, input, obj, + inputs = this._form.getElementsByTagName('input'), + inputsLen = inputs.length, + baseLayer; + + this._handlingClick = true; + + // Convert ID to pos + var id2pos = {}; + for (i in this._layers) { + id2pos[this._layers[i].id] = i; + } + + for (i = 0; i < inputsLen; i++) { + input = inputs[i]; + obj = this._layers[id2pos[input.layerId]]; + + if (input.checked && !this._map.hasLayer(obj.layer)) { + this._map.addLayer(obj.layer); + if (!obj.overlay) { + baseLayer = obj.layer; + } + } else if (!input.checked && this._map.hasLayer(obj.layer)) { + this._map.removeLayer(obj.layer); + } + } + + if (baseLayer) { + this._map.setZoom(this._map.getZoom()); + this._map.fire('baselayerchange', {layer: baseLayer}); + } + + this._handlingClick = false; + } +} diff --git a/src/leaflet/control/LinkControl.ts b/src/leaflet/control/LinkControl.ts index 72da8ec..5dbb432 100644 --- a/src/leaflet/control/LinkControl.ts +++ b/src/leaflet/control/LinkControl.ts @@ -1,51 +1,26 @@ import L, {ControlOptions} from 'leaflet'; - -export interface LinkControlOptions extends ControlOptions {} +import {useStore} from "@/store"; export class LinkControl extends L.Control { - options: LinkControlOptions + // @ts-ignore + options: ControlOptions - onAdd(map) { - this._map = map; - this._container = L.DomUtil.create('div', 'dynmap-link'); + private _map ?: L.Map; - this._linkButton = this._createButton( - 'Link', 'dynmap-link-button', this._follow, this); - - this._container.appendChild(this._linkButton); - return this._container; + constructor(options: ControlOptions) { + super(options); } - getContainer() { - return this._container; - } + onAdd(map: L.Map) { + const linkButton = L.DomUtil.create('button', 'leaflet-control-link') as HTMLButtonElement; - getPosition() { - return this.options.position; - } + linkButton.type = 'button'; + linkButton.title = 'Link'; + linkButton.addEventListener('click', () => { + const projection = useStore().state.currentProjection; + console.log(projection.latLngToLocation(this._map!.getCenter(), 64)); + }); - _createButton(title, className, fn, context) { - const link = document.createElement('a'); - link.href = '#'; - link.title = title; - link.className = className; - link.onmouseover = function () { - link.href = dynmap.getLink(); - }; - - L.DomEvent.disableClickPropagation(link); - L.DomEvent.addListener(link, 'click', L.DomEvent.preventDefault); - L.DomEvent.addListener(link, 'click', fn, context); - - return link; - } - - _follow() { - // var url = dynmap.getLink(); - // window.location = url; + return linkButton; } } - -// var link = new dynmapLink(); -// dynmap.map.addControl(link); -// } diff --git a/src/leaflet/control/LogoControl.js b/src/leaflet/control/LogoControl.js deleted file mode 100644 index a3787a0..0000000 --- a/src/leaflet/control/LogoControl.js +++ /dev/null @@ -1,50 +0,0 @@ -import L from 'leaflet'; - -const LogoControl = L.Control.extend({ - onAdd: function (map) { - this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); - this._map = map; - this._update(); - return this._container; - }, - - getPosition: function () { - if (configuration.position == 'top-left') - return 'topleft'; - else if (configuration.position == 'top-right') - return 'topright'; - else if (configuration.position == 'bottom-left') - return 'bottomleft'; - else - return 'bottomright'; - }, - - getContainer: function () { - return this._container; - }, - - _update: function () { - if (!this._map) return; - var c = this._container; - if (configuration.linkurl) { - c = $('').attr('href', configuration.linkurl).appendTo(c)[0]; - } - if (configuration.logourl) { - $(c).append($('').attr('src', configuration.logourl).attr('alt', configuration.text).appendTo(c)[0]); - } else { - $(c).text(configuration.text); - } - } -}); -// -// dynmap.map.options.attributionControl = false; -// if (dynmap.map.attributionControl) { -// dynmap.map.removeControl(dynmap.map.attributionControl); -// dynmap.map.attributionControl = null; -// } -// var l = new Logo(); -// dynmap.map.addControl(l); -// } -// ; - -export default LogoControl; \ No newline at end of file diff --git a/src/leaflet/control/LogoControl.ts b/src/leaflet/control/LogoControl.ts new file mode 100644 index 0000000..ed0d5b5 --- /dev/null +++ b/src/leaflet/control/LogoControl.ts @@ -0,0 +1,45 @@ +import L, {ControlOptions} from 'leaflet'; + +export interface LogoControlOptions extends ControlOptions { + url?: string; + image?: string; + text: string; +} + +export class LogoControl extends L.Control { + // @ts-ignore + options: LogoControlOptions; + + constructor(options: LogoControlOptions) { + super(options); + } + + onAdd(map: L.Map) { + const container = L.DomUtil.create('div', 'leaflet-control-logo'); + let link; + + if (this.options.url) { + link = L.DomUtil.create('a', '', container) as HTMLAnchorElement; + link.href = this.options.url; + } + + if (this.options.image) { + const image = L.DomUtil.create('img', '', link) as HTMLImageElement; + image.src = this.options.image; + image.alt = this.options.text; + } else { + container.textContent = this.options.text; + } + + return container; + } +} + +// +// dynmap.map.options.attributionControl = false; +// if (dynmap.map.attributionControl) { +// dynmap.map.removeControl(dynmap.map.attributionControl); +// dynmap.map.attributionControl = null; +// } +// } +// ; diff --git a/src/leaflet/icon/DynmapIcon.ts b/src/leaflet/icon/DynmapIcon.ts new file mode 100644 index 0000000..109be28 --- /dev/null +++ b/src/leaflet/icon/DynmapIcon.ts @@ -0,0 +1,69 @@ +import L, {PointTuple} from 'leaflet'; + +export interface DynmapIconOptions { + icon: string; + label: string; + dimensions: PointTuple; + showLabel: boolean; + isHtml?: boolean; + className?: string; +} + +export class DynmapIcon extends L.Icon { + static defaultOptions: DynmapIconOptions = { + icon: 'default', + label: '', + dimensions: [16,16], + showLabel: false, + isHtml: false, + className: '', + }; + private _container?: HTMLDivElement; + + constructor(options: DynmapIconOptions) { + super(Object.assign(DynmapIcon.defaultOptions, options)); + } + + createIcon(oldIcon: HTMLElement) { + if (oldIcon) { + L.DomUtil.remove(oldIcon); + } + + const + img = document.createElement('img'), + label = document.createElement('span'), + url = `${window.config.url.markers}_markers_/${this.options.icon}.png`; + + // this._container.classList.add('Marker', 'mapMarker'); + this._container = document.createElement('div'); + this._container.classList.add('leaflet-div-icon'); + this._container.style.backgroundColor = 'pink'; + this._container.style.width = '16px'; + this._container.style.height = '16px'; + + if(this.options.className) { + this._container.classList.add(this.options.className); + } + + img.classList.add('markerIcon', `markerIcon${this.options.dimensions.join('x')}`); + img.src = url; + + label.classList.add(this.options.showLabel ? 'markerName-show' : 'markerName'); + label.classList.add(/*'markerName_' + set.id,*/ `markerName${this.options.dimensions.join('x')}`); + + if (this.options.isHtml) { + label.insertAdjacentHTML('afterbegin', this.options.label); + } else { + label.textContent = this.options.label; + } + + // this._container.insertAdjacentElement('beforeend', img); + // this._container.insertAdjacentElement('beforeend', label); + + return this._container; + } + + update() { + + } +} diff --git a/src/leaflet/icon/PlayerIcon.ts b/src/leaflet/icon/PlayerIcon.ts index 66a81fb..f1aee05 100644 --- a/src/leaflet/icon/PlayerIcon.ts +++ b/src/leaflet/icon/PlayerIcon.ts @@ -1,7 +1,12 @@ -import L, {DivIconOptions} from 'leaflet'; +import L, {MarkerOptions} from 'leaflet'; import {DynmapPlayer} from "@/dynmap"; -export interface PlayerIconOptions extends DivIconOptions { +const noSkinImage: HTMLImageElement = document.createElement('img'); +noSkinImage.height = 16; +noSkinImage.width = 16; +noSkinImage.src = 'images/player.png'; + +export interface PlayerIconOptions extends MarkerOptions { smallFace: boolean, showSkinFace: boolean, showBody: boolean, @@ -37,23 +42,15 @@ export class PlayerIcon extends L.DivIcon { this._container = document.createElement('div'); - // var markerPosition = dynmap.getProjection().fromLocationToLatLng(player.location); - // player.marker.setLatLng(markerPosition); - this._container.classList.add('Marker', 'playerMarker', 'leaflet-marker-icon'); - this._playerImage = document.createElement('img'); - this._playerImage.classList.add(this.options.smallFace ? 'playerIconSm' : 'playerIcon'); - this._playerImage.src = 'images/player.png'; - this._playerName = document.createElement('span'); this._playerName.classList.add(this.options.smallFace ? 'playerNameSm' : 'playerName'); this._playerName.innerText = player.name; - this._container.insertAdjacentElement('beforeend', this._playerImage); - this._container.insertAdjacentElement('beforeend', this._playerName); - if (this.options.showSkinFace) { + this._playerImage = document.createElement('img'); + this._playerImage.classList.add(this.options.smallFace ? 'playerIconSm' : 'playerIcon'); // if (this.options.smallFace) { // getMinecraftHead(player.account, 16, head => { @@ -68,13 +65,19 @@ export class PlayerIcon extends L.DivIcon { // this._playerImage!.src = head.src; // }); // } + } else { + this._playerImage = noSkinImage.cloneNode(false) as HTMLImageElement; + this._playerImage.classList.add(this.options.smallFace ? 'playerIconSm' : 'playerIcon'); } + this._container.appendChild(this._playerImage); + this._container.appendChild(this._playerName); + if (this.options.showHealth) { this._playerHealth = document.createElement('div'); this._playerHealth.classList.add(this.options.smallFace ? 'healthContainerSm' : 'healthContainer'); - this._container.insertAdjacentElement('beforeend', this._playerHealth) + this._container.appendChild(this._playerHealth) this._playerHealthBar = document.createElement('div'); this._playerHealthBar.classList.add('playerHealth'); @@ -88,11 +91,11 @@ export class PlayerIcon extends L.DivIcon { this._playerHealthBg.classList.add('playerHealthBackground'); this._playerArmourBar.classList.add('playerArmorBackground'); - this._playerHealthBg.insertAdjacentElement('beforeend', this._playerHealthBar); - this._playerArmourBg.insertAdjacentElement('beforeend', this._playerArmourBar); + this._playerHealthBg.appendChild(this._playerHealthBar); + this._playerArmourBg.appendChild(this._playerArmourBar); - this._playerHealth.insertAdjacentElement('beforeend', this._playerHealthBg); - this._playerHealth.insertAdjacentElement('beforeend', this._playerArmourBg); + this._playerHealth.appendChild(this._playerHealthBg); + this._playerHealth.appendChild(this._playerArmourBg); this._playerHealth.hidden = true; } else { @@ -103,14 +106,20 @@ export class PlayerIcon extends L.DivIcon { } update() { + if(!this._container) { + return; + } + this._playerName!.innerText = this._player!.name; - if (this._player.health !== undefined && this._player.armor !== undefined) { - this._playerHealth!.hidden = false; - this._playerHealthBar!.style.width = Math.ceil(this._player.health * 2.5) + 'px'; - this._playerArmourBar!.style.width = Math.ceil(this._player.armor * 2.5) + 'px'; - } else { - this._playerHealth!.hidden = true; + if(this.options.showHealth) { + if (this._player.health !== undefined && this._player.armor !== undefined) { + this._playerHealth!.hidden = false; + this._playerHealthBar!.style.width = Math.ceil(this._player.health * 2.5) + 'px'; + this._playerArmourBar!.style.width = Math.ceil(this._player.armor * 2.5) + 'px'; + } else { + this._playerHealth!.hidden = true; + } } } } diff --git a/src/leaflet/map.ts b/src/leaflet/map.ts new file mode 100644 index 0000000..ff99c6f --- /dev/null +++ b/src/leaflet/map.ts @@ -0,0 +1,29 @@ +import L from 'leaflet'; + +L.Map.include({ + _initControlPos: function () { + const corners: any = this._controlCorners = {}, + l = 'leaflet-', + container = this._controlContainer = + L.DomUtil.create('div', l + 'control-container', this._container); + + function createCorner(vSide: string, hSide: string) { + const className = l + vSide + ' ' + l + hSide; + + corners[`${vSide}${hSide}`] = L.DomUtil.create('div', className, container); + } + + createCorner('top', 'left'); + createCorner('top', 'bar'); + createCorner('top', 'right'); + createCorner('top', 'center'); + createCorner('bottom', 'center'); + createCorner('bottom', 'bar'); + createCorner('bottom', 'left'); + createCorner('bottom', 'right'); + }, + + getUrl() { + + } +}); \ No newline at end of file diff --git a/src/leaflet/mapType/HDMapType.ts b/src/leaflet/mapType/HDMapType.ts index c877c29..15be0df 100644 --- a/src/leaflet/mapType/HDMapType.ts +++ b/src/leaflet/mapType/HDMapType.ts @@ -19,11 +19,11 @@ export class HDMapType extends DynmapTileLayer { options.minZoom = 0; L.Util.setOptions(this, options); - this._projection = new HDProjection({ + this._projection = Object.freeze(new HDProjection({ mapToWorld: this._mapSettings.mapToWorld, worldToMap: this._mapSettings.worldToMap, nativeZoomLevels: this._mapSettings.nativeZoomLevels, - }); + })); } getTileName(coords: Coordinate) { diff --git a/src/leaflet/marker/DynmapMarker.ts b/src/leaflet/marker/DynmapMarker.ts new file mode 100644 index 0000000..3ce119c --- /dev/null +++ b/src/leaflet/marker/DynmapMarker.ts @@ -0,0 +1,25 @@ +import L, {LatLng} from "leaflet"; + +export class DynmapMarker extends L.Marker { + options: { + image: null, + showLabel: true, + label: "", + minZoom: 0, + maxZoom: Infinity, + } + + constructor(latlng: LatLng, options) { + options.icon = new LabelledIcon(player, { + smallFace: options.smallFace, + showSkinFace: options.showSkinFace, + showBody: options.showBody, + showHealth: options.showHealth, + }); + super(latlng, options); + } + + update() { + + } +} diff --git a/src/leaflet/marker/PlayerMarker.ts b/src/leaflet/marker/PlayerMarker.ts index d8c0756..fc9b325 100644 --- a/src/leaflet/marker/PlayerMarker.ts +++ b/src/leaflet/marker/PlayerMarker.ts @@ -13,9 +13,10 @@ export class PlayerMarker extends L.Marker { private _player: DynmapPlayer; constructor(player: DynmapPlayer, options: PlayerMarkerOptions) { - super(new LatLng(0,0), options); + super(new LatLng(0, 0), options); this._player = player; options.draggable = false; + options.icon = new PlayerIcon(player, { smallFace: options.smallFace, showSkinFace: options.showSkinFace, @@ -24,6 +25,24 @@ export class PlayerMarker extends L.Marker { }); L.Util.setOptions(this, options); - //this._latlng = toLatLng(latlng); //TODO + } + + getIcon(): PlayerIcon { + return this.options.icon as PlayerIcon; + } + + panTo() { + if (!this._map) { + return; + } + + this._map.panTo(this.getLatLng(), { + animate: false, + noMoveStart: true, + }); + } + + _resetZIndex() { + //Don't chnage the zindex } } diff --git a/src/leaflet/projection/DynmapProjection.ts b/src/leaflet/projection/DynmapProjection.ts index e5d2038..4977389 100644 --- a/src/leaflet/projection/DynmapProjection.ts +++ b/src/leaflet/projection/DynmapProjection.ts @@ -10,16 +10,16 @@ export interface DynmapProjection { export class DynmapProjection extends L.Class { - constructor(options: DynmapProjectionOptions) { + constructor(options?: DynmapProjectionOptions) { super(); L.Util.setOptions(this, options); } locationToLatLng(location: Coordinate): L.LatLng { - throw new Error("fromLocationToLatLng not implemented"); + return new L.LatLng(location.x, location.z); } latLngToLocation(latLng: L.LatLng, y: number): Coordinate { - throw new Error("fromLatLngToLocation not implemented"); + return {x: latLng.lat, y, z: latLng.lng}; } } diff --git a/src/leaflet/tileLayer/DynmapTileLayer.ts b/src/leaflet/tileLayer/DynmapTileLayer.ts index 8a496ab..08b0203 100644 --- a/src/leaflet/tileLayer/DynmapTileLayer.ts +++ b/src/leaflet/tileLayer/DynmapTileLayer.ts @@ -9,17 +9,30 @@ export interface DynmapTileLayerOptions extends TileLayerOptions { export interface DynmapTileLayer extends L.TileLayer { options: DynmapTileLayerOptions; - _projection: any; - _mapSettings: any; - _cachedTileUrls: any; - _namedTiles: any; + _projection: DynmapProjection; + _mapSettings: DynmapMap; + _cachedTileUrls: Map; + _namedTiles: Map; + _tileTemplate: DynmapTileElement; + _loadQueue: DynmapTileElement[]; + _loadingTiles: Set; locationToLatLng(location: Coordinate): L.LatLng; latLngToLocation(latLng: L.LatLng): Coordinate; } -export interface DynmapTile extends HTMLImageElement { +export interface DynmapTile { + active?: boolean; + coords: Coords; + current: boolean; + el: DynmapTileElement; + loaded?: Date; + retain?: boolean; + complete: boolean; +} + +export interface DynmapTileElement extends HTMLImageElement { tileName: string; } @@ -36,8 +49,10 @@ export interface TileInfo { } export class DynmapTileLayer extends L.TileLayer { + constructor(options: DynmapTileLayerOptions) { super('', options); + L.Util.setOptions(this, options); if (options.mapSettings === null) { throw new TypeError("mapSettings missing"); @@ -45,9 +60,22 @@ export class DynmapTileLayer extends L.TileLayer { this._projection = new DynmapProjection({}); this._mapSettings = options.mapSettings; - this._cachedTileUrls = {}; - this._namedTiles = {}; - L.Util.setOptions(this, options); + this._cachedTileUrls = Object.seal(new Map()); + this._namedTiles = Object.seal(new Map()); + this._loadQueue = []; + this._loadingTiles = Object.seal(new Set()); + + this._tileTemplate = L.DomUtil.create('img', 'leaflet-tile') as DynmapTileElement; + this._tileTemplate.style.width = this._tileTemplate.style.height = this.options.tileSize + 'px'; + this._tileTemplate.alt = ''; + this._tileTemplate.tileName = ''; + this._tileTemplate.setAttribute('role', 'presentation'); + + Object.seal(this._tileTemplate); + + if(this.options.crossOrigin || this.options.crossOrigin === '') { + this._tileTemplate.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; + } } getTileName(coords: Coordinate): string { @@ -56,20 +84,20 @@ export class DynmapTileLayer extends L.TileLayer { getTileUrl(coords: Coordinate) { const tileName = this.getTileName(coords); - let url = this._cachedTileUrls[tileName]; + let url = this._cachedTileUrls.get(tileName); if (!url) { const path = escape(`${this._mapSettings.world.name}/${tileName}`); url = `${window.config.url.tiles}${path}`; - this._cachedTileUrls[tileName] = url; + this._cachedTileUrls.set(tileName, url); } return url; } updateNamedTile(name: string) { - const tile = this._namedTiles[name]; - delete this._cachedTileUrls[name]; + const tile = this._namedTiles.get(name); + this._cachedTileUrls.delete(name); if (tile) { //tile.src = this._cachedTileUrls[name] = this.getTileUrl(name); @@ -77,32 +105,68 @@ export class DynmapTileLayer extends L.TileLayer { } createTile(coords: Coords, done: DoneCallback) { - const tile = super.createTile.call(this, coords, done) as DynmapTile, - name = this.getTileName(coords); + //Clone template image instead of creating a new one + const tile = this._tileTemplate.cloneNode(false) as DynmapTileElement; - tile.tileName = name; + tile.tileName = this.getTileName(coords); + tile.dataset.src = this.getTileUrl(coords); - // console.log("Adding " + tile.tileName); - this._namedTiles[name] = tile; + this._namedTiles.set(tile.tileName, tile); + this._loadQueue.push(tile); + + //Use addEventListener here + tile.onload = () => { + this._tileOnLoad(done, tile); + this._loadingTiles.delete(tile); + this._tickLoadQueue(); + }; + tile.onerror = () => { + this._tileOnError(done, tile, {name: 'Error', message: 'Error'}); + this._loadingTiles.delete(tile); + this._tickLoadQueue(); + }; + + this._tickLoadQueue(); return tile; } + _tickLoadQueue() { + if (this._loadingTiles.size > 4) { + return; + } + + const tile = this._loadQueue.shift(); + + if (!tile) { + return; + } + + this._loadingTiles.add(tile); + tile.src = tile.dataset.src as string; + } + // stops loading all tiles in the background layer _abortLoading() { let tile; + for (const i in this._tiles) { if (!Object.prototype.hasOwnProperty.call(this._tiles, i)) { continue; } - tile = this._tiles[i]; + tile = this._tiles[i] as DynmapTile; if (tile.coords.z !== this._tileZoom) { - if (tile.loaded && tile.el && (tile.el as DynmapTile).tileName) { - // console.log("Aborting " + (tile.el as DynmapTile).tileName); - delete this._namedTiles[(tile.el as DynmapTile).tileName]; + if (tile.loaded && tile.el && tile.el.tileName) { + this._namedTiles.delete(tile.el.tileName); } + + if(this._loadQueue.includes(tile.el)) { + this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1); + } + + this._loadingTiles.delete(tile.el); } } @@ -110,18 +174,25 @@ export class DynmapTileLayer extends L.TileLayer { } _removeTile(key: string) { - const tile = this._tiles[key]; + const tile = this._tiles[key] as DynmapTile; if (!tile) { return; } - const tileName = (tile.el as DynmapTile).tileName; + const tileName = tile.el.tileName as string; if (tileName) { - // console.log("Removing " + tileName); - delete this._namedTiles[tileName]; - delete this._cachedTileUrls[tileName]; + this._namedTiles.delete(tileName); + this._cachedTileUrls.delete(tileName); + this._loadingTiles.delete(tile.el); + + if(this._loadQueue.includes(tile.el)) { + this._loadQueue.splice(this._loadQueue.indexOf(tile.el), 1); + } + + tile.el.onerror = null; + tile.el.onload = null; } // @ts-ignore diff --git a/src/main.ts b/src/main.ts index cd4f023..58a2319 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,10 +4,10 @@ import {store} from "@/store"; import 'leaflet/dist/leaflet.css'; import 'normalize-scss/sass/normalize/_import-now.scss'; -import './assets/css/dynmap_style.css'; -import './assets/css/rtgame.css'; +import '@/scss/style.scss'; +// import './assets/css/rtgame.css'; const app = createApp(App).use(store); -app.config.performance = true; +// app.config.performance = true; app.mount('#mcmap'); \ No newline at end of file diff --git a/src/scss/_placeholders.scss b/src/scss/_placeholders.scss new file mode 100644 index 0000000..738b6b5 --- /dev/null +++ b/src/scss/_placeholders.scss @@ -0,0 +1,39 @@ +%button { + appearance: none; + border: none; + box-shadow: none; + background-color: $global-background; + color: $global-text-color; + border-radius: $global-border-radius; + cursor: pointer; + display: block; + + &:hover, &.active { + background-color: #cccccc; + color: #222222; + } + + &:focus { + outline-color: #cccccc; + outline-width: 0.2rem; + } + + &:active { + background-color: #eeeeee; + color: #121212; + } +} + +%panel { + background-color: $global-background; + color: $global-text-color; + border-radius: $global-border-radius; + display: flex; + flex-direction: column; + padding: 1.5rem; + position: relative; + + h2:first-child { + margin-top: 0; + } +} \ No newline at end of file diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index e69de29..b8061f6 100644 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -0,0 +1,4 @@ +$global-text-color: #cccccc; +$global-border-radius: 1rem; +$global-background: #222222; +$global-focus-color: #cccccc; \ No newline at end of file diff --git a/src/scss/leaflet/_controls.scss b/src/scss/leaflet/_controls.scss new file mode 100644 index 0000000..e05ad0f --- /dev/null +++ b/src/scss/leaflet/_controls.scss @@ -0,0 +1,164 @@ +.leaflet-control { + background-color: $global-background; + border-radius: $global-border-radius; + margin: 0; + box-sizing: border-box; + overflow: hidden; + + a, button { + @extend %button; + } +} + +.leaflet-bar { + display: flex; + align-items: center; + padding: 0; + border: none; + + a { + border-radius: 0; + border-bottom: 0.1rem solid #333333; + } +} + +.leaflet-touch { + .leaflet-bar, .leaflet-control-layers { + border: none; + } + + .leaflet-control-layers-toggle { + width: 5rem; + height: 5rem; + } + + .leaflet-top { + .leaflet-bar a { + height: 5rem; + width: 5rem; + line-height: 5rem; + + &:first-child { + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; + } + + &:last-child { + border-bottom-left-radius: 1rem; + border-bottom-right-radius: 1rem; + } + } + } +} + +.leaflet-control-link { + @extend %button; + width: 5rem; + height: 5rem; + background: $global-background url('../assets/images/link.png') no-repeat center; + background-size: 3.2rem 3.2rem; +} + +.leaflet-control-coordinates { + display: flex; + align-items: center; + padding: 0.5rem 1.5rem; + + .value { + font-size: 1.6rem; + line-height: 1; + font-family: monospace; + white-space: pre; + + &[data-label]:before { + content: attr(data-label); + display: block; + line-height: 1; + margin-bottom: 0.5rem; + font-size: 1.4rem; + font-family: Raleway, sans-serif;; + } + + & + .value { + margin-left: 2rem; + } + } +} + +.leaflet-control-layers { + width: 5rem; + border: none; +} + +.leaflet-control-logo { + width: 5rem; + height: 5rem; + + a { + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + } +} + +.leaflet-top, .leaflet-bottom, +.leaflet-left, .leaflet-right { + display: flex; +} + +.leaflet-left { + padding-left: 1rem; + + .leaflet-control { + margin: 0; + } +} + +.leaflet-top { + padding-top: 1rem; + flex-direction: column; + + .leaflet-control { + order: 2; + min-width: 5rem; + + & + .leaflet-control { + margin-top: 1rem; + } + } + + .leaflet-bar { + flex-direction: column; + + a { + width: 5rem; + height: 5rem; + line-height: 5rem; + } + } + + .leaflet-control-logo { + order: 1; + margin-bottom: 1rem; + margin-top: 0 !important; + + & + .leaflet-control-logo { + margin-top: 1rem !important; + } + } +} + +.leaflet-bottom { + padding-bottom: 1rem; + + &.leaflet-left .leaflet-control + .leaflet-control { + margin-left: 1rem; + } +} + +.leaflet-control-layers-toggle { + width: 5rem; + height: 5rem; +} \ No newline at end of file diff --git a/src/scss/leaflet/_popups.scss b/src/scss/leaflet/_popups.scss new file mode 100644 index 0000000..fc45c4b --- /dev/null +++ b/src/scss/leaflet/_popups.scss @@ -0,0 +1,13 @@ +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background-color: $global-background; + color: $global-text-color; +} + +.leaflet-popup-content-wrapper { + border-radius: $global-border-radius; +} + +.leaflet-popup-content { + margin: 1.5rem; + word-break: break-all; +} \ No newline at end of file diff --git a/src/scss/style.scss b/src/scss/style.scss new file mode 100644 index 0000000..16c29a7 --- /dev/null +++ b/src/scss/style.scss @@ -0,0 +1,658 @@ +/* TILE DEBUGGING */ +/*.leaflet-tile { + margin: -1; + border: 1px solid red; +}*/ +@import "variables"; +@import "placeholders"; +@import "leaflet/controls"; +@import "leaflet/popups"; + +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: local('Raleway'), local('Raleway-Regular'), url(https://fonts.gstatic.com/s/raleway/v14/1Ptug8zYS_SKggPNyC0ITw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +* { + scrollbar-width: thin; + scrollbar-color: $global-text-color transparent; +} + +*::-webkit-scrollbar { + width: 1.2rem; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background-color: #333333; + border-radius: 2rem; + transition: background 1s ease-in; +} + +*:hover::-webkit-scrollbar-thumb { + background-color: $global-focus-color; +} + +*::-webkit-scrollbar-button { + display: none; +} + +html { + font-size: .625em; +} + +body { + font-family: Raleway, sans-serif; + color: $global-text-color; + text-shadow: 0.1rem 0.1rem #000000; + letter-spacing: 0.02rem; + font-size: 1.2em; +} + +html, body { + background-color: $global-background; + height: 100%; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: normal; + margin-top: 0; +} + +h1 { + font-size: 3rem; +} + +h2 { + font-size: 2rem; + line-height: 2.4rem; + margin-bottom: 1rem; +} + +button { + @extend %button; +} + +.dynmap { + height: 100%; +} + +/* End of new things */ + +.dynmap .map .tile img, img { + image-rendering: pixelated; +} + + +/******************* + * Map Setup + */ + +/* Map Controls */ +.gmnoprint{ + margin-top:-75px; + margin-left:-20px; +} + + +/******************* + * Alerts are pretty. + */ + +.alertbox { + position: fixed; + width: 50%; + z-index: 999; + + top: 0; + left: 0; + right: 0; + + text-align: center; + font-size: 16px; + font-weight: bold; + + color: #fff; + background: #c00; + + border-color: #a00; + + margin: auto; + padding: 8px; +} + + +/******************* + * shared rules + */ + +.dynmap ul, .dynmap li { + list-style: none; + + padding: 0; + margin: 0; +} + +.maplist li a, +.playerlist li a { + outline: none; + text-decoration: none; +} + +.alertbox, +.largeclock { + border-style: solid; + border-width: 0 1px 1px 1px; + + + + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); + border-radius: 0 0 3px 3px; +} + +/******************* + * sidebar panels + */ + + + + +/******************* + * Sidebar clock style + */ +/* +.dynmap .clock { + display: inline-block; + height: 16px; + z-index:50; + + font-weight: bold; + background-repeat: no-repeat; + + padding-left: 20px; + margin-left: 8px; +} +*/ +.largeclock.digitalclock { + text-align: center; + font-size: 50px; + font-weight: bold; +} + +.digitalclock { + text-align: center; + font-size: 20px; + font-weight:bold; +} + +.digitalclock.night { + /* background-image: url(../assets/images/clock_night.png); */ + color: #dff; +} + +.digitalclock.day { + /* background-image: url(../assets/images/clock_day.png); */ + color: #fd3; +} + +.digitalclock.night, .digitalclock.day { + transition: color 8s 8s linear; +} + + +/******************* + * Large clock style + */ + +.largeclock { + position: absolute; + top: 0; + left: 0; + right: 0; + border-color: rgba(0,0,0,0.5); + width: 150px; + height: 60px; + background: rgba(0,0,0,0.6); + z-index:50; + + margin: auto; +} + +.timeofday { + background-repeat: no-repeat; +} + +.timeofday.sun { + background-image: url(../assets/images/sun.png); +} + +.timeofday.moon { + background-image: url(../assets/images/moon.png); +} + +.timeofday.digitalclock { + position: relative; + bottom: 25px; +} + +/******************* + * Clock weather style + */ + +.weather { + position: absolute; + top: 5px; + right: 0; + width: 32px; + height: 32px; + display: block; + background-repeat: no-repeat; +} + +.weather.sunny_day { + background-image: url(../assets/images/weather_sunny_day.png); +} + +.weather.stormy_day { + background-image: url(../assets/images/weather_stormy_day.png); +} +.weather.thunder_day { + background-image: url(../assets/images/weather_thunder_day.png); +} + +.weather.sunny_night { + background-image: url(../assets/images/weather_sunny_night.png); +} + +.weather.stormy_night { + background-image: url(../assets/images/weather_stormy_night.png); +} +.weather.thunder_night { + background-image: url(../assets/images/weather_thunder_night.png); +} + +/******************* + * players on the map + */ + +/* smooth player movements (contrib from KillahKiwi) */ +.dynmap .playerMarker { + transition: transform 0.3s ease-in 0s; +} + +.dynmap .playerIcon { + margin-top: -16px; + margin-left: -16px; + width: 32px; + height: 32px; +} + +.dynmap .playerIconSm { + margin-top: -8px; + margin-left: -8px; + width: 16px; + height: 16px; +} + +.dynmap .playerName { + position: absolute; + top: -19px; + left: 18px; + z-index:20; + + white-space: nowrap; + + color: $global-text-color; + background: #121212; + padding: 0.2rem; +} + +.dynmap .playerNameSm { + position: absolute; + top: -16px; + left: 10px; + + white-space: nowrap; + + color: $global-text-color; + background: #121212; + padding: 0.2rem; +} + +.dynmap .playerNameNoHealth { + top: -7px; +} + +.dynmap .healthContainer { + display: block; + position: absolute; + top: 1px; + left: 18px; + + width: 50px; + + background: rgba(0,0,0,0.6); + padding: 2px; + + border-radius: 3px; + + z-index: 21; +} + +.dynmap .healthContainerSm { + display: block; + position: absolute; + top: -2px; + left: 10px; + + width: 50px; + + background: rgba(0,0,0,0.6); + padding: 2px; + + border-radius: 3px; +} + +.dynmap .playerHealth { + height: 7px; + + background: url(../assets/images/heart.png) repeat-x left center; +} + +.dynmap .playerHealthBackground { + height: 7px; + width: 50px; + + background: url(../assets/images/heart_depleted.png) repeat-x left center; +} + +.dynmap .playerArmor { + height: 7px; + + background: url(../assets/images/armor.png) repeat-x left center; +} + +.dynmap .playerArmorBackground { + height: 7px; + width: 50px; + + background: url(../assets/images/armor_depleted.png) repeat-x left center; +} + + +/******************* + * Compass + */ + +.compass, .compass_NE, .compass_SE, .compass_NW, .compass_SW { + display: block; + position: absolute; + z-index: 10; + top: 20px; + right: 32px; + height: 84px; + width: 83px; + background-repeat: no-repeat; +} + +.compass, .compass_SE { + background-image: url(../assets/images/compass.png); +} + +.compass_NE { + background-image: url(../assets/images/compass_NE.png); +} + +.compass_NW { + background-image: url(../assets/images/compass_NW.png); +} + +.compass_SW { + background-image: url(../assets/images/compass_SW.png); +} + +.compass_flat, .compass_N, .compass_E, .compass_W, .compass_S { + top: 10px; + right: 21px; + + height: 105px; + width: 105px; +} + +.compass_flat, .compass_S { + background-image: url(../assets/images/compass_flat.png); +} + +.compass_N { + background-image: url(../assets/images/compass_N.png); +} + +.compass_E { + background-image: url(../assets/images/compass_E.png); +} + +.compass_W { + background-image: url(../assets/images/compass_W.png); +} + +.mobilecompass { + top: 5px; + right: 10px; + height: 42px; + width: 42px; + background-size: cover; +} + +/******************* + * Chat + */ + +.chat { + position: absolute; + bottom: 0; + left: 32px; + z-index:50; + + border-color: rgba(0,0,0,0.5); + background: rgba(0,0,0,0.6); + + border-style: solid; + border-width: 1px 1px 0 1px; + + border-radius: 3px 3px 0 0; + + margin-left: 10px; +} + +.chatinput { + + width: 608px; + height: 16px; + + outline: none; + color: #fff; + border: 0; + background: rgba(0, 0, 0, 0.6) url(../assets/images/chat_cursor.png) no-repeat 1px center; + + margin: 4px; + padding: 1px 1px 1px 15px; +} + +.chatsendbutton { + background-color: #bbb; +} + +.loginbutton { + color: #000; + font-family: sans-serif; + font-size: 11px; + border: 1px solid rgba(128,128,128,0.6); + background-color: #bbb; + padding: 2px; + border-radius: 5px; + cursor: pointer; + margin: 0; +} + +.messagelist { + color: white; + overflow: hidden; + + width: 622px; + max-height: 6em; + + margin: 4px 4px 0 4px; + padding: 1px; +} + +.scrollback:hover { + overflow-y: auto !important; +} + + +.messagerow { + position: relative; + max-height: 200px; + + left: 0; + bottom: 0; + + color: #fff; + font-weight: bold; +} + +.messageicon { + position: relative; + top: 1px; + left: 0; +} + +.messagetext { + position: relative; + top: -3px; + left: 0; +} + +.leaflet-popup { + color: black; +} + +.balloonmessage { + word-wrap: break-word; +} + +/* Marker styles */ +.dynmap .mapMarker .markerName { + display: none; + z-index: 101; +} + +.dynmap .mapMarker:hover .markerName, +.dynmap .mapMarker .markerName-show { + display: block; + position: absolute; + z-index: 16; + + white-space: nowrap; + + color: #fff; + background: rgba(0,0,0,0.6); + padding: 2px; + + border-radius: 3px; +} + +.dynmap .mapMarker .markerName16x16 { + top: -6px; + left: 10px; +} + +.dynmap .mapMarker .markerName8x8 { + top: -4px; + left: 6px; +} + +.dynmap .mapMarker .markerName32x32 { + top: -8px; + left: 18px; +} + +.dynmap .mapMarker .markerIcon16x16 { + transform: translate(-50%, -50%); + width: 16px; + height: 16px; +} + +.dynmap .mapMarker .markerIcon8x8 { + transform: translate(-50%, -50%); + width: 8px; + height: 8px; +} + +.dynmap .mapMarker .markerIcon32x32 { + transform: translate(-50%, -50%); + width: 32px; + height: 32px; +} + +.dynmap .mapMarker .markerName_offline_players { + font-style: italic; +} + +/* Login/register panel */ +.dynmaplogin { + text-align: center; + width: 100%; + font-weight: bold; + color: #FFFFFF; + background: #000000; +} + +table.loginregister { + color: #ffffff; + border: 1px solid rgba(64,64,64,0.6); + background: #bbb; + font-weight: bold; + margin: auto; +} + +td.login { + vertical-align: top; + color: #000000; + background-color: #bbb; + border: 1px solid rgba(64,64,64,0.6); + font-weight: bold; + margin: 2em; + width: 40em; +} + +td.register { + vertical-align: top; + color: #000000; + background-color: #bbb; + border: 1px solid rgba(64,64,64,0.6); + font-weight: bold; + margin: 2em; + width: 40em; +} + +div.statusmessage { + color: #FF0000; + font-weight: bold; + font-size: 24px; + +} + +.logincontainer { + background-color: rgba(0,0,0,0.0); +} + +.pinnedloginbutton { + margin-right: 201px; +} diff --git a/src/store/action-types.ts b/src/store/action-types.ts index cdb0b41..78b36c4 100644 --- a/src/store/action-types.ts +++ b/src/store/action-types.ts @@ -1,4 +1,6 @@ export enum ActionTypes { LOAD_CONFIGURATION = "loadConfiguration", GET_UPDATE = "getUpdate", + GET_MARKER_SETS = "getMarkerSets", + SET_PLAYERS = "setPlayers", } \ No newline at end of file diff --git a/src/store/actions.ts b/src/store/actions.ts index db3a3a7..2866f98 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -4,7 +4,7 @@ import {State} from "@/store/state"; import {ActionTypes} from "@/store/action-types"; import API from '@/api'; import {Mutations} from "@/store/mutations"; -import {DynmapConfigurationResponse, DynmapUpdateResponse} from "@/dynmap"; +import {DynmapConfigurationResponse, DynmapMarkerSet, DynmapPlayer, DynmapUpdateResponse} from "@/dynmap"; type AugmentedActionContext = { commit( @@ -20,6 +20,13 @@ export interface Actions { [ActionTypes.GET_UPDATE]( {commit}: AugmentedActionContext, ):Promise + [ActionTypes.GET_MARKER_SETS]( + {commit}: AugmentedActionContext, + ):Promise> + [ActionTypes.SET_PLAYERS]( + {commit}: AugmentedActionContext, + payload: Set + ):Promise> } export const actions: ActionTree & Actions = { @@ -32,28 +39,63 @@ export const actions: ActionTree & Actions = { if(config.config.defaultWorld && config.config.defaultMap) { commit(MutationTypes.SET_CURRENT_MAP, { - world: config.config.defaultWorld, - map: config.config.defaultMap + worldName: config.config.defaultWorld, + mapName: config.config.defaultMap }); } return config; }); }, - [ActionTypes.GET_UPDATE]({commit, state}) { + [ActionTypes.GET_UPDATE]({commit, dispatch, state}) { if(!state.currentWorld) { return Promise.reject("No current world"); } return API.getUpdate(state.updateRequestId, state.currentWorld.name, state.updateTimestamp.getUTCMilliseconds()).then(update => { - commit(MutationTypes.SET_PLAYERS, update.players); - commit(MutationTypes.SET_TIME_OF_DAY, update.timeOfDay); - commit(MutationTypes.SET_RAINING, update.raining); - commit(MutationTypes.SET_THUNDERING, update.thundering); + commit(MutationTypes.SET_WORLD_STATE, update.worldState); commit(MutationTypes.SET_UPDATE_TIMESTAMP, new Date(update.timestamp)); commit(MutationTypes.INCREMENT_REQUEST_ID, undefined); - return update; + return dispatch(ActionTypes.SET_PLAYERS, update.players).then(() => { + return update; + }); + }); + }, + [ActionTypes.SET_PLAYERS]({commit, state}, players: Set) { + const keep: Set = new Set(); + + for(const player of players) { + keep.add(player.account); + } + + //Remove any players that aren't in the set + commit(MutationTypes.SYNC_PLAYERS, keep); + + const processQueue = (players: Set, resolve: Function) => { + commit(MutationTypes.SET_PLAYERS_ASYNC, players); + + if(!players.size) { + resolve(); + } else { + requestAnimationFrame(() => processQueue(players, resolve)); + } + } + + //Set players every frame until done + return new Promise((resolve) => { + requestAnimationFrame(() => processQueue(players, resolve)); + }); + }, + [ActionTypes.GET_MARKER_SETS]({commit, state}) { + if(!state.currentWorld) { + return Promise.reject("No current world"); + } + + return API.getMarkerSets(state.currentWorld.name).then(markerSets => { + commit(MutationTypes.SET_MARKER_SETS, markerSets); + + return markerSets; }); } } \ No newline at end of file diff --git a/src/store/getters.ts b/src/store/getters.ts index e3c1965..41bafeb 100644 --- a/src/store/getters.ts +++ b/src/store/getters.ts @@ -3,10 +3,20 @@ import {State} from "@/store/state"; export type Getters = { playerMarkersEnabled(state: State): boolean; + coordinatesControlEnabled(state: State): boolean; + clockControlEnabled(state: State): boolean; } export const getters: GetterTree & Getters = { playerMarkersEnabled(state: State): boolean { return state.components.playerMarkers !== undefined; + }, + + coordinatesControlEnabled(state: State): boolean { + return state.components.coordinatesControl !== undefined; + }, + + clockControlEnabled(state: State): boolean { + return state.components.clockControl !== undefined; } } \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index 42607c6..7a5dfae 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,7 +1,7 @@ import { createStore, Store as VuexStore, - createLogger, + // createLogger, CommitOptions, DispatchOptions, } from 'vuex'; @@ -37,7 +37,7 @@ export const store = createStore({ mutations, getters, actions, - plugins: [createLogger()], + // plugins: [createLogger()], }); // define your own `useStore` composition function diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts index 193c962..4d98dcd 100644 --- a/src/store/mutation-types.ts +++ b/src/store/mutation-types.ts @@ -3,12 +3,16 @@ export enum MutationTypes { SET_MESSAGES = 'setMessages', SET_WORLDS = 'setWorlds', SET_COMPONENTS = 'setComponents', + SET_MARKER_SETS = 'setMarkerSets', ADD_WORLD = 'addWorld', - SET_TIME_OF_DAY = 'setTimeOfDay', - SET_RAINING = 'setRaining', - SET_THUNDERING = 'setThundering', + SET_WORLD_STATE = 'setWorldState', SET_UPDATE_TIMESTAMP = 'setUpdateTimestamp', INCREMENT_REQUEST_ID = 'incrementRequestId', SET_PLAYERS = 'setPlayers', + SET_PLAYERS_ASYNC = 'setPlayersAsync', + SYNC_PLAYERS = 'syncPlayers', SET_CURRENT_MAP = 'setCurrentMap', + SET_CURRENT_PROJECTION = 'setCurrentProjection', + FOLLOW_PLAYER = 'followPlayer', + CLEAR_FOLLOW = 'clearFollow', } \ No newline at end of file diff --git a/src/store/mutations.ts b/src/store/mutations.ts index 1a897dc..7d3a1fd 100644 --- a/src/store/mutations.ts +++ b/src/store/mutations.ts @@ -1,11 +1,19 @@ import {MutationTree} from "vuex"; import {MutationTypes} from "@/store/mutation-types"; import {State} from "@/store/state"; -import {DynmapComponentConfig, DynmapMessageConfig, DynmapPlayer, DynmapServerConfig, DynmapWorld} from "@/dynmap"; +import { + DynmapComponentConfig, DynmapMarkerSet, + DynmapMessageConfig, + DynmapPlayer, + DynmapServerConfig, + DynmapWorld, + DynmapWorldState +} from "@/dynmap"; +import {DynmapProjection} from "@/leaflet/projection/DynmapProjection"; export type CurrentMapPayload = { - world: string - map: string + worldName: string; + mapName: string; } export type Mutations = { @@ -13,40 +21,43 @@ export type Mutations = { [MutationTypes.SET_MESSAGES](state: S, messages: DynmapMessageConfig): void [MutationTypes.SET_WORLDS](state: S, worlds: Array): void [MutationTypes.SET_COMPONENTS](state: S, worlds: DynmapComponentConfig): void + [MutationTypes.SET_MARKER_SETS](state: S, worlds: Map): void [MutationTypes.ADD_WORLD](state: S, world: DynmapWorld): void - [MutationTypes.SET_TIME_OF_DAY](state: S, time: number): void - [MutationTypes.SET_RAINING](state: S, raining: boolean): void - [MutationTypes.SET_THUNDERING](state: S, thundering: boolean): void + [MutationTypes.SET_WORLD_STATE](state: S, worldState: DynmapWorldState): void [MutationTypes.SET_UPDATE_TIMESTAMP](state: S, time: Date): void [MutationTypes.INCREMENT_REQUEST_ID](state: S): void - [MutationTypes.SET_PLAYERS](state: S, players: Array): void + // [MutationTypes.SET_PLAYERS](state: S, players: Array): void + [MutationTypes.SET_PLAYERS_ASYNC](state: S, players: Set): void + [MutationTypes.SYNC_PLAYERS](state: S, keep: Set): void [MutationTypes.SET_CURRENT_MAP](state: S, payload: CurrentMapPayload): void + [MutationTypes.SET_CURRENT_PROJECTION](state: S, payload: DynmapProjection): void + [MutationTypes.FOLLOW_PLAYER](state: S, payload: DynmapPlayer): void + [MutationTypes.CLEAR_FOLLOW](state: S, a?: void): void } export const mutations: MutationTree & Mutations = { + // Sets configuration options from the initial config fetch [MutationTypes.SET_CONFIGURATION](state: State, config: DynmapServerConfig) { state.configuration = Object.assign(state.configuration, config); }, + + //Set messsages from the initial config fetch [MutationTypes.SET_MESSAGES](state: State, messages: DynmapMessageConfig) { state.messages = Object.assign(state.messages, messages); }, + //Sets the list of worlds, and their settings, from the initial config fetch [MutationTypes.SET_WORLDS](state: State, worlds: Array) { state.worlds.clear(); state.maps.clear(); - state.configuration.followMap = undefined; - state.configuration.followZoom = undefined; - state.configuration.defaultMap = undefined; - state.configuration.defaultWorld = undefined; - state.currentMap = undefined; state.currentWorld = undefined; state.following = undefined; - state.timeOfDay = 0; - state.raining = false; - state.thundering = false; + state.currentWorldState.timeOfDay = 0; + state.currentWorldState.raining = false; + state.currentWorldState.thundering = false; worlds.forEach(world => { state.worlds.set(world.name, world); @@ -54,45 +65,74 @@ export const mutations: MutationTree & Mutations = { }); }, + //Sets the state and settings of optional compontents, from the initial config fetch [MutationTypes.SET_COMPONENTS](state: State, components: DynmapComponentConfig) { state.components = components; }, + //Sets the existing marker sets from the last marker fetch + [MutationTypes.SET_MARKER_SETS](state: State, markerSets: Map) { + state.markerSets = markerSets; + }, + [MutationTypes.ADD_WORLD](state: State, world: DynmapWorld) { state.worlds.set(world.name, world); }, - [MutationTypes.SET_TIME_OF_DAY](state: State, time: number) { - if (time < 0 || time > 24000) { - throw new RangeError("Time must be between 0 and 24000"); - } - - state.timeOfDay = time; - }, - - [MutationTypes.SET_RAINING](state: State, raining: boolean) { - state.raining = raining; - }, - - [MutationTypes.SET_THUNDERING](state: State, thundering: boolean) { - state.thundering = thundering; + //Sets the current world state from the last update fetch + [MutationTypes.SET_WORLD_STATE](state: State, worldState: DynmapWorldState) { + state.currentWorldState = Object.assign(state.currentWorldState, worldState); }, + //Sets the timestamp of the last update fetch [MutationTypes.SET_UPDATE_TIMESTAMP](state: State, timestamp: Date) { state.updateTimestamp = timestamp; }, + //Increments the request id for the next update fetch [MutationTypes.INCREMENT_REQUEST_ID](state: State) { state.updateRequestId++; }, - [MutationTypes.SET_PLAYERS](state: State, players: Array) { - const existingPlayers: Set = new Set(); + // [MutationTypes.SET_PLAYERS](state: State, players: Array) { + // const existingPlayers: Set = new Set(); + // + // players.forEach(player => { + // existingPlayers.add(player.account); + // + // if (state.players.has(player.account)) { + // const existing = state.players.get(player.account); + // + // existing!.health = player.health; + // existing!.armor = player.armor; + // existing!.location = Object.assign(existing!.location, player.location); + // existing!.name = player.name; + // existing!.sort = player.sort; + // } else { + // state.players.set(player.account, { + // account: player.account, + // health: player.health, + // armor: player.armor, + // location: player.location, + // name: player.name, + // sort: player.sort, + // }); + // } + // }); + // + // for (const key of state.players.keys()) { + // if (!existingPlayers.has(key)) { + // state.players.delete(key); + // } + // } + // }, - players.forEach(player => { - existingPlayers.add(player.account); + //Set up to 10 players at once, returning the rest for future setting + [MutationTypes.SET_PLAYERS_ASYNC](state: State, players: Set) { + let count = 0; - if (state.players.has(player.account)) { + for(const player of players) { + if(state.players.has(player.account)) { const existing = state.players.get(player.account); existing!.health = player.health; @@ -110,27 +150,54 @@ export const mutations: MutationTree & Mutations = { sort: player.sort, }); } - }); - for (const key of state.players.keys()) { - if (!existingPlayers.has(key)) { + players.delete(player); + + if(++count >= 10) { + return players; + } + } + }, + + //Removes all players not found in the provided keep set + [MutationTypes.SYNC_PLAYERS](state: State, keep: Set) { + for(const [key, player] of state.players) { + if(!keep.has(player.account)) { state.players.delete(key); } } }, - [MutationTypes.SET_CURRENT_MAP](state: State, {world, map}) { - const mapName = [world, map].join('_'); + [MutationTypes.SET_CURRENT_MAP](state: State, {worldName, mapName}) { + mapName = [worldName, mapName].join('_'); - if(!state.worlds.has(world)) { - throw new RangeError(`Unknown world ${world}`); + if(!state.worlds.has(worldName)) { + throw new RangeError(`Unknown world ${worldName}`); } if(!state.maps.has(mapName)) { - throw new RangeError(`Unknown map ${map}`); + throw new RangeError(`Unknown map ${mapName}`); + } + + const newWorld = state.worlds.get(worldName); + + if(state.currentWorld !== newWorld) { + state.currentWorld = state.worlds.get(worldName); + state.markerSets.clear(); } - state.currentWorld = state.worlds.get(world); state.currentMap = state.maps.get(mapName); }, + + [MutationTypes.SET_CURRENT_PROJECTION](state: State, projection) { + state.currentProjection = projection; + }, + + [MutationTypes.FOLLOW_PLAYER](state: State, player: DynmapPlayer) { + state.following = player; + }, + + [MutationTypes.CLEAR_FOLLOW](state: State) { + state.following = undefined; + } } \ No newline at end of file diff --git a/src/store/state.ts b/src/store/state.ts index efc14d8..6aac7cb 100644 --- a/src/store/state.ts +++ b/src/store/state.ts @@ -1,11 +1,12 @@ import { DynmapComponentConfig, - DynmapMap, + DynmapMap, DynmapMarker, DynmapMarkerSet, DynmapMessageConfig, DynmapPlayer, DynmapServerConfig, - DynmapWorld + DynmapWorld, DynmapWorldState } from "@/dynmap"; +import {DynmapProjection} from "@/leaflet/projection/DynmapProjection"; export type State = { configuration: DynmapServerConfig; @@ -15,16 +16,15 @@ export type State = { worlds: Map; maps: Map; players: Map; + markerSets: Map; following?: DynmapPlayer; // currentServer?: string; + currentWorldState: DynmapWorldState; currentWorld?: DynmapWorld; currentMap?: DynmapMap; - - raining: boolean; - thundering: boolean; - timeOfDay: number; + currentProjection: DynmapProjection; updateRequestId: number; updateTimestamp: Date; @@ -62,22 +62,43 @@ export const state: State = { anonymousQuit: '', }, - worlds: new Map(), - maps: new Map(), - players: new Map(), + worlds: new Map(), //Defined (loaded) worlds with maps from configuration.json + maps: new Map(), //Defined maps from configuration.json + players: new Map(), //Online players from world.json + markerSets: new Map(), //Markers from world_markers.json. Contents of each set isn't reactive for performance reasons. + //Dynmap optional components components: { + // "markers" component. Only used for default showLabels settings + markers: { + showLabels: false, + }, + // Optional "playermarkers" component. Settings for online player markers. + // If not present, player markers will be disabled playerMarkers: undefined, - }, - raining: false, - thundering: false, - timeOfDay: 0, + //Optional "coords" component. Adds control showing coordinates on map mouseover + coordinatesControl: undefined, + + //Optional clock component. Used for both "digitalclock" and "timeofdayclock". Shows world time/weather. + clockControl: undefined, + + //Optional "link" component. Adds button to get url for current position + linkControl: false, + + logoControls: [], + }, following: undefined, currentWorld: undefined, + currentWorldState: { + raining: false, + thundering: false, + timeOfDay: 0, + }, currentMap: undefined, + currentProjection: new DynmapProjection(), //Projection for converting location <-> latlg. Object itself isn't reactive for performance reasons updateRequestId: 0, updateTimestamp: new Date(),