├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── dist
└── spa
│ ├── assets
│ ├── KFOkCnqEu92Fr1MmgVxIIzQ-34e9582c.woff
│ ├── KFOlCnqEu92Fr1MmEU9fBBc--9ce7f3ac.woff
│ ├── KFOlCnqEu92Fr1MmSU5fBBc--bf14c7d7.woff
│ ├── KFOlCnqEu92Fr1MmWUlfBBc--e0fd57c0.woff
│ ├── KFOlCnqEu92Fr1MmYUtfBBc--f6537e32.woff
│ ├── KFOmCnqEu92Fr1Mu4mxM-f2abf7fb.woff
│ ├── MainLayout-b2302958.css
│ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNa-fd84f88b.woff
│ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-4a4dbc62.woff2
│ └── index-012a8cd7.css
│ ├── favicon.ico
│ ├── icon.png
│ ├── icons
│ ├── favicon-128x128.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ └── favicon-96x96.png
│ ├── index.html
│ ├── multiple_tile.png
│ ├── robots.txt
│ ├── single_tile.png
│ └── thirtytwo-9-82-180.png
├── index.html
├── jsconfig.json
├── mt-rainier1.png
├── mt-rainier2.png
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
├── icon.png
├── icons
│ ├── favicon-128x128.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ └── favicon-96x96.png
├── multiple_tile.png
├── robots.txt
├── single_tile.png
└── thirtytwo-9-82-180.png
├── quasar.config.js
├── src-electron
├── electron-flag.d.ts
├── electron-main.js
├── electron-preload.js
├── icon.png
└── icons
│ ├── icon.icns
│ ├── icon.ico
│ └── icon.png
└── src
├── App.vue
├── boot
└── .gitkeep
├── components
├── ReloadPrompt.vue
├── help.vue
├── mapbox-map-viewer.vue
├── maptiler-map-viewer.vue
├── side-nav.vue
└── wieghtmap-viewer.vue
├── css
├── app.scss
├── quasar.variables.scss
└── styles.css
├── layouts
└── MainLayout.vue
├── mapbox-gl-draw-assisted-rectangle-mode
├── .babelrc
├── .gitignore
├── README.md
├── dist
│ ├── DrawAssistedRectangle.js
│ └── DrawAssistedRectangle.min.js
├── draw-assisted-rectangle.gif
├── index.html
├── package.json
└── src
│ └── DrawAssistedRectangle.js
├── maptiler-gl-button-control
├── .ignore
├── Example
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ └── styles.css
├── README.md
├── example.png
├── index.js
└── package.json
├── pages
├── ErrorNotFound.vue
└── IndexPage.vue
├── router
├── index.js
└── routes.js
└── utilities
├── combine-tiles-jimp.js
├── emitter.js
├── fs-helpers.js
├── idb-keyval-iife.js
└── map-utils.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .thumbs.db
3 | node_modules
4 |
5 | # Quasar core related directories
6 | .quasar
7 | package-lock.json
8 |
9 |
10 | # Cordova related directories and files
11 | /src-cordova/node_modules
12 | /src-cordova/platforms
13 | /src-cordova/plugins
14 | /src-cordova/www
15 |
16 | # Capacitor related directories and files
17 | /src-capacitor/www
18 | /src-capacitor/node_modules
19 |
20 | # Log files
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | # Editor directories and files
26 | .idea
27 | *.suo
28 | *.ntvs*
29 | *.njsproj
30 | *.sln
31 | !/electron-builder.yml
32 | electron-builder.yml
33 | /electron-builder.yml
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Daniel Elebash
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This app is no longer maintained please see the new app here https://github.com/delebash/unreal_map_bridge
2 |
3 | # New live site https://map.justgeektechs.com/
4 |
5 | # Unreal Mapbox Bridge
6 |
7 | #### Use real world heightmap data from Mapbox and automatically convert it to an Unreal heightmap image
8 |
9 | # Live site [here](https://terrain.justgeektechs.com/)
10 |
11 |
12 | # Plugin version for Unreal Egine 5 UnrealMapboxBridge
13 |
14 | # Tutorial Playlist
15 |
16 | https://www.youtube.com/playlist?list=PLFCVXzupw1r_7ExUSGDxHGHU-gPRxOGeZ
17 |
18 | Get Help here Discord Server
19 |
20 | For what is coming next check the **RoadMap **
21 |
22 | Other free Unreal projects
23 |
24 | https://github.com/delebash/unreal_vault_organizer
25 |
26 |
27 | # Updates: 10/28/2022
28 |
29 | ## Added:
30 |
31 | **Blur Radius** -- This will apply a blur to the heightmap. It can be useful to reduce sharp edges and artifacts. The greater the number the greater the blur.
32 |
33 | ## Added Buttons:
34 |
35 | **Send to Terrain Magic** -- (only works with custom Terrain Magic code -- pm me on my discord channel if you want it). If you use the Terrain Magic plugin from the UE market place then this will load your landscape into Terrain Magic.
36 |
37 | **Copy Bounds for Blender Osm** -- If you use the Blender Osm plugin to generate real world landscapes, this will copy the coordinates you need to paste into the Blender Osm Plugin. Osm has it's own map app but if you use this map app you can still have that capability.
38 |
39 | **Copy Slippy Tile String** -- This will copy the Slippy Tile String Info. Slippy Tile is a format for identifying Tile Information. It is in the format x,y,z where z = zoom level. Terrain Magic uses the Slippy Tile String, so until Send To Terrain Magic is fixed you can use this to copy and paste into Terrain Magic.
40 |
41 | **Dist folder** -- contains compiled web app. You should be able to run it from any web server.
42 |
43 |
44 | ## Install the dependencies
45 | ```bash
46 | npm install
47 | ```
48 |
49 | ### Start the app in development mode (hot-code reloading, error reporting, etc.)
50 |
51 | ```bash
52 | npm start
53 | ```
54 |
55 | > NOTE: When running the development server you will need to disble cors for your browser or the api calls to Mapbox will not work. For Edge/Chrome there is a good plugin that I use to do this. See https://microsoftedge.microsoft.com/addons/detail/cors-unblock/hkjklmhkbkdhlgnnfbbcihcajofmjgbh
56 | >
57 |
58 | ## Build
59 | ```bash
60 | npm run build
61 | ```
62 |
63 | ## Setup
64 |
65 | When you initially run the application you will have to set some data.
66 |
67 | **Settings Tab**
68 |
69 | 1) Enter a mapbox access token under the Settings Tab in the Mapbox Access Token File field
70 |
71 | To get an access token you can create a free [mapbox account](https://www.mapbox.com/). Then goto your account page and copy the default access token or create a new one.
72 |
73 | 2) Choose a download directory from the Settings screen.
74 |
75 | 3) Click the Save Settings button
76 |
77 | **Map Tab**
78 |
79 | Left click and hold to drag around the map
80 | Right click and hold to change the angle of the map
81 |
82 | Scroll wheel to zoom in out
83 |
84 | Game keys for navigation are also enabled WSAD
85 |
86 | Type in a name or coordinates in the search box
87 |
88 | Left click on the tile square you want to select. It will turn blue when selected.
89 |
90 | You will see a preview of what the heightmap will look like as well as some statistics.
91 |
92 | Click the download button to download the selected tile 16 bit heightmap file.
93 |
94 | Select Terrain size youu want to use for your Unreal Landscape size.
95 |
96 | The Scale number is correct but may look large in Unreal. You might want to use a different scale number when you import into Unreal.
97 |
98 |
99 | **Manually resize method if you want to edit your hegitmap in a photo editor**
100 |
101 | **Convert image to Unreal Landscape Size**
102 |
103 | See Unreal Recommended Landscape Sizes [here](https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/Landscape/TechnicalGuide/)
104 |
105 | Resizing/Resampling an image for Unreal Landscapes has been added to the software. Just select your Landscape size before you download your heightmap. As an alternative to resizing in the application you can use other software to resize to custom sizes.
106 |
107 | Programs you can use to resample your image to the landscape size you are using.
108 |
109 | [GIMP](https://www.gimp.org/https://www.gimp.org/), [Affinity Photo](https://affinity.serif.com/en-us/photo/), [Photoshop](https://www.adobe.com/products/photoshop/landpa.html).
110 | [Terra Sculptor](http://www.demenzunmedia.com/home/terresculptor/) -- is an awesome free program for creating and manipulating heightmap images. It even has preset landscape sizes for Unreal. To enable UDK go to Settings > Dimensions and check UDK Landscape.
111 |
112 | The principle is the same for all.
113 |
114 | Example: **GIMP**
115 |
116 | 1) Choose File > Open then open the sixteen-x-x-x.png file for the tile you selected. The numbers indicate the selected tile.
117 |
118 | 2) Choose Layer > Scale Layer
119 | 3) Type in the width and height (should be the same as in height: 2017 width: 2017)
120 | 4) Set the Interpolation to NoHalo and click Scale
121 | 5) Choose File > Export as and name your converted file.
122 | 6) On the popup dialog box named "Export image as PNG" leave all defaults and click Export.
123 |
124 |
125 | Import the heightmap into Unreal per normal procedure. You will need to adjust the Z-scale to the Z-scale shown on the app.
126 |
127 | Example imported landscape standing on top of Mt. Rainier
128 |
129 | 
130 |
131 | 
132 |
133 |
134 | *Inspired by and some code used from this [project](https://github.com/colkassad/terrain-rgb-height). A Big thanks to Shane Brennan ([colkassad](https://github.com/colkassad)).*
135 |
--------------------------------------------------------------------------------
/dist/spa/assets/KFOkCnqEu92Fr1MmgVxIIzQ-34e9582c.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOkCnqEu92Fr1MmgVxIIzQ-34e9582c.woff
--------------------------------------------------------------------------------
/dist/spa/assets/KFOlCnqEu92Fr1MmEU9fBBc--9ce7f3ac.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOlCnqEu92Fr1MmEU9fBBc--9ce7f3ac.woff
--------------------------------------------------------------------------------
/dist/spa/assets/KFOlCnqEu92Fr1MmSU5fBBc--bf14c7d7.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOlCnqEu92Fr1MmSU5fBBc--bf14c7d7.woff
--------------------------------------------------------------------------------
/dist/spa/assets/KFOlCnqEu92Fr1MmWUlfBBc--e0fd57c0.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOlCnqEu92Fr1MmWUlfBBc--e0fd57c0.woff
--------------------------------------------------------------------------------
/dist/spa/assets/KFOlCnqEu92Fr1MmYUtfBBc--f6537e32.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOlCnqEu92Fr1MmYUtfBBc--f6537e32.woff
--------------------------------------------------------------------------------
/dist/spa/assets/KFOmCnqEu92Fr1Mu4mxM-f2abf7fb.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/KFOmCnqEu92Fr1Mu4mxM-f2abf7fb.woff
--------------------------------------------------------------------------------
/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-fd84f88b.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-fd84f88b.woff
--------------------------------------------------------------------------------
/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-4a4dbc62.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-4a4dbc62.woff2
--------------------------------------------------------------------------------
/dist/spa/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/favicon.ico
--------------------------------------------------------------------------------
/dist/spa/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/icon.png
--------------------------------------------------------------------------------
/dist/spa/icons/favicon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/icons/favicon-128x128.png
--------------------------------------------------------------------------------
/dist/spa/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/dist/spa/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/dist/spa/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/dist/spa/index.html:
--------------------------------------------------------------------------------
1 |
Unreal Mapbox Bridge
2 |
3 |
--------------------------------------------------------------------------------
/dist/spa/multiple_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/multiple_tile.png
--------------------------------------------------------------------------------
/dist/spa/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
--------------------------------------------------------------------------------
/dist/spa/single_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/single_tile.png
--------------------------------------------------------------------------------
/dist/spa/thirtytwo-9-82-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/dist/spa/thirtytwo-9-82-180.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Unreal Mapbox Bridge
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
18 |
20 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "src/*": [
6 | "src/*"
7 | ],
8 | "app/*": [
9 | "*"
10 | ],
11 | "components/*": [
12 | "src/components/*"
13 | ],
14 | "layouts/*": [
15 | "src/layouts/*"
16 | ],
17 | "pages/*": [
18 | "src/pages/*"
19 | ],
20 | "assets/*": [
21 | "src/assets/*"
22 | ],
23 | "boot/*": [
24 | "src/boot/*"
25 | ],
26 | "stores/*": [
27 | "src/stores/*"
28 | ],
29 | "vue$": [
30 | "node_modules/vue/dist/vue.runtime.esm-bundler.js"
31 | ]
32 | }
33 | },
34 | "exclude": [
35 | "dist",
36 | ".quasar",
37 | "node_modules"
38 | ]
39 | }
--------------------------------------------------------------------------------
/mt-rainier1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/mt-rainier1.png
--------------------------------------------------------------------------------
/mt-rainier2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/mt-rainier2.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "unreal-mapbox-bridge",
3 | "version": "2.8.0",
4 | "description": "Import real world locations into Unreal using Mapbox",
5 | "productName": "Unreal Mapbox Bridge",
6 | "author": "Daniel Elebash ",
7 | "private": true,
8 | "homepage": "http://delebash.github.io/unreal_mapbox_bridge",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/delebash/unreal_mapbox_bridge"
12 | },
13 | "scripts": {
14 | "start": "quasar dev",
15 | "electron": "quasar dev -m electron",
16 | "build-spa": "quasar build",
17 | "build-electron": "quasar build -m electron",
18 | "publish-electron": "quasar build --debug -m electron -P always",
19 | "debug": "quasar dev --debug -m electron -t mat -- --remote-debugging-port=9222 --inspect-brk=5858"
20 | },
21 | "dependencies": {
22 | "@delebash/mapbox-gl-button-control": "^1.0.4",
23 | "@geostarters/mapbox-gl-draw-rectangle-assisted-mode": "^3.0.4",
24 | "@mapbox/mapbox-gl-draw": "^1.4.1",
25 | "@mapbox/mapbox-gl-geocoder": "^5.0.1",
26 | "@mapbox/mapbox-sdk": "^0.15.2",
27 | "@mapbox/tilebelt": "^1.0.2",
28 | "@maptiler/client": "^1.5.0",
29 | "@maptiler/geocoding-control": "^0.0.90",
30 | "@maptiler/sdk": "^1.0.12",
31 | "@quasar/extras": "^1.16.4",
32 | "@turf/turf": "^6.5.0",
33 | "idb-keyval": "^6.2.1",
34 | "image-js": "^0.35.3",
35 | "jimp": "^0.22.8",
36 | "lodash": "^4.17.21",
37 | "mapbox-gl": "^2.15.0",
38 | "mapbox-gl-draw-rectangle-mode": "^1.0.4",
39 | "mitt": "^3.0.0",
40 | "quasar": "^2.12.0",
41 | "tiles-in-bbox": "^1.0.2",
42 | "vue": "^3.3.4",
43 | "vue-router": "^4.2.2"
44 | },
45 | "devDependencies": {
46 | "@quasar/app-vite": "^1.4.3",
47 | "autoprefixer": "^10.4.14",
48 | "electron": "^25.1.0",
49 | "workbox-build": "^7.0.0",
50 | "workbox-cacheable-response": "^7.0.0",
51 | "workbox-core": "^7.0.0",
52 | "workbox-expiration": "^7.0.0",
53 | "workbox-precaching": "^7.0.0",
54 | "workbox-routing": "^7.0.0",
55 | "workbox-strategies": "^7.0.0"
56 | },
57 | "overrides": {
58 | "vite": "^4.0.0",
59 | "@vitejs/plugin-vue": "^4.0.0"
60 | },
61 | "engines": {
62 | "node": "^18 || ^16 || ^14.19",
63 | "npm": ">= 6.13.4",
64 | "yarn": ">= 1.21.1"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // https://github.com/michael-ciniawsky/postcss-load-config
3 |
4 | module.exports = {
5 | plugins: [
6 | // https://github.com/postcss/autoprefixer
7 | require('autoprefixer')({
8 | overrideBrowserslist: [
9 | 'last 4 Chrome versions',
10 | 'last 4 Firefox versions',
11 | 'last 4 Edge versions',
12 | 'last 4 Safari versions',
13 | 'last 4 Android versions',
14 | 'last 4 ChromeAndroid versions',
15 | 'last 4 FirefoxAndroid versions',
16 | 'last 4 iOS versions'
17 | ]
18 | })
19 |
20 | // https://github.com/elchininet/postcss-rtlcss
21 | // If you want to support RTL css, then
22 | // 1. yarn/npm install postcss-rtlcss
23 | // 2. optionally set quasar.config.js > framework > lang to an RTL language
24 | // 3. uncomment the following line:
25 | // require('postcss-rtlcss')
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/favicon.ico
--------------------------------------------------------------------------------
/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/icon.png
--------------------------------------------------------------------------------
/public/icons/favicon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/icons/favicon-128x128.png
--------------------------------------------------------------------------------
/public/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/multiple_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/multiple_tile.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
3 |
--------------------------------------------------------------------------------
/public/single_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/single_tile.png
--------------------------------------------------------------------------------
/public/thirtytwo-9-82-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/public/thirtytwo-9-82-180.png
--------------------------------------------------------------------------------
/quasar.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | /*
4 | * This file runs in a Node context (it's NOT transpiled by Babel), so use only
5 | * the ES6 features that are supported by your Node version. https://node.green/
6 | */
7 |
8 | // Configuration for your app
9 | // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
10 |
11 |
12 | const {configure} = require('quasar/wrappers');
13 |
14 |
15 | module.exports = configure(function (/* ctx */) {
16 | return {
17 |
18 |
19 | // https://v2.quasar.dev/quasar-cli/prefetch-feature
20 | // preFetch: true,
21 |
22 | // app boot file (/src/boot)
23 | // --> boot files are part of "main.js"
24 | // https://v2.quasar.dev/quasar-cli/boot-files
25 | boot: [],
26 |
27 | // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
28 | css: [
29 | 'app.scss'
30 | ],
31 |
32 | // https://github.com/quasarframework/quasar/tree/dev/extras
33 | extras: [
34 | // 'ionicons-v4',
35 | // 'mdi-v5',
36 | // 'fontawesome-v6',
37 | // 'eva-icons',
38 | // 'themify',
39 | // 'line-awesome',
40 | // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
41 |
42 | 'roboto-font', // optional, you are not bound to it
43 | 'material-icons', // optional, you are not bound to it
44 | ],
45 |
46 | // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
47 | build: {
48 | target: {
49 | browser: ['esnext'],
50 | node: 'node16'
51 | },
52 |
53 | vueRouterMode: 'hash', // available values: 'hash', 'history'
54 | // vueRouterBase,
55 | // vueDevtools,
56 | // vueOptionsAPI: false,
57 |
58 | // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
59 |
60 | // publicPath: '/',
61 | // analyze: true,
62 | // env: {browser:true},
63 | // rawDefine: {}
64 | // ignorePublicFolder: true,
65 | // minify: false,
66 | // polyfillModulePreload: true,
67 | // distDir
68 |
69 | // extendViteConf (viteConf) {},
70 | // viteVuePluginOptions: {},
71 |
72 |
73 | // vitePlugins: [
74 | // [ 'package-name', { ..options.. } ]
75 | // ]
76 | },
77 |
78 | // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
79 | devServer: {
80 | // https: true
81 | open: true // opens browser window automatically
82 | },
83 |
84 | // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
85 | framework: {
86 | config: {
87 | loading: { /* look at QuasarConfOptions from the API card */},
88 | notify: { /* look at QuasarConfOptions from the API card */},
89 | dialog: { /* look at QuasarConfOptions from the API card */}
90 | },
91 |
92 | // iconSet: 'material-icons', // Quasar icon set
93 | // lang: 'en-US', // Quasar language pack
94 |
95 | // For special cases outside of where the auto-import strategy can have an impact
96 | // (like functional components as one of the examples),
97 | // you can manually specify Quasar components/directives to be available everywhere:
98 | //
99 | // components: [],
100 | // directives: [],
101 |
102 | // Quasar plugins
103 | plugins: [
104 | 'Notify',
105 | 'Dialog',
106 | 'Loading'
107 | ]
108 | },
109 |
110 | // animations: 'all', // --- includes all animations
111 | // https://v2.quasar.dev/options/animations
112 | animations: [],
113 |
114 | // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
115 | // sourceFiles: {
116 | // rootComponent: 'src/App.vue',
117 | // router: 'src/router/index',
118 | // store: 'src/store/index',
119 | // registerServiceWorker: 'src-pwa/register-service-worker',
120 | // serviceWorker: 'src-pwa/custom-service-worker',
121 | // pwaManifestFile: 'src-pwa/manifest.json',
122 | // electronMain: 'src-electron/electron-main',
123 | // electronPreload: 'src-electron/electron-preload'
124 | // },
125 |
126 | // https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
127 | ssr: {
128 | // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
129 | // will mess up SSR
130 |
131 | // extendSSRWebserverConf (esbuildConf) {},
132 | // extendPackageJson (json) {},
133 |
134 | pwa: false,
135 |
136 | // manualStoreHydration: true,
137 | // manualPostHydrationTrigger: true,
138 |
139 | prodPort: 3000, // The default port that the production server should use
140 | // (gets superseded if process.env.PORT is specified at runtime)
141 |
142 | middlewares: [
143 | 'render' // keep this as last one
144 | ]
145 | },
146 |
147 | // https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
148 | pwa: {
149 | workboxOptions: {
150 | skipWaiting: true,
151 | clientsClaim: true
152 | },
153 | workboxMode: 'generateSW', // or 'injectManifest'
154 | injectPwaMetaTags: true,
155 | swFilename: 'sw.js',
156 | manifestFilename: 'manifest.json',
157 | useCredentialsForManifestTag: false,
158 | // extendGenerateSWOptions (cfg) {}
159 | // extendInjectManifestOptions (cfg) {},
160 | // extendManifestJson (json) {}
161 | // extendPWACustomSWConf (esbuildConf) {}
162 | },
163 |
164 | // Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
165 | cordova: {
166 | // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
167 | },
168 |
169 | // Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
170 | capacitor: {
171 | hideSplashscreen: true
172 | },
173 |
174 | // Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
175 | electron: {
176 | // extendElectronMainConf (esbuildConf)
177 | // extendElectronPreloadConf (esbuildConf)
178 |
179 | inspectPort: 5858,
180 |
181 | bundler: 'builder', // 'packager' or 'builder'
182 |
183 | packager: {
184 | // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
185 |
186 | // OS X / Mac App Store
187 | // appBundleId: '',
188 | // appCategoryType: '',
189 | // osxSign: '',
190 | // protocol: 'myapp://path',
191 |
192 | // Windows only
193 | // win32metadata: { ... }
194 | },
195 | builder: {
196 | // https://www.electron.build/configuration/configuration
197 | appId: 'unreal-mapbox-bridge',
198 | files: [
199 | "!**/node_modules/*"
200 | ],
201 | publish: {
202 | 'provider': 'github'
203 | },
204 | win: {// configuration parameters of installation software under Windows
205 | target: [
206 | "portable" // single exe
207 | ]
208 | },
209 | portable: {
210 | "artifactName": "Unreal Mapbox Bridge.exe"
211 | }
212 | // nsis: {// NSIS configuration parameters
213 | // oneClick: false, // click to open
214 | // deleteAppDataOnUninstall: true,
215 | // allowToChangeInstallationDirectory: true, // allows the user to choose the installation location
216 | // perMachine: true
217 | // }
218 | }
219 | },
220 |
221 | // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
222 | bex: {
223 | contentScripts: [
224 | 'my-content-script'
225 | ],
226 |
227 | // extendBexScriptsConf (esbuildConf) {}
228 | // extendBexManifestJson (json) {}
229 | }
230 | }
231 | });
232 |
--------------------------------------------------------------------------------
/src-electron/electron-flag.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // THIS FEATURE-FLAG FILE IS AUTOGENERATED,
3 | // REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
4 | import "quasar/dist/types/feature-flag";
5 |
6 | declare module "quasar/dist/types/feature-flag" {
7 | interface QuasarFeatureFlags {
8 | electron: true;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src-electron/electron-main.js:
--------------------------------------------------------------------------------
1 | import {app, BrowserWindow, nativeTheme, Menu} from 'electron'
2 | import path from 'path'
3 | import os from 'os'
4 |
5 | app.commandLine.appendSwitch('enable-features', "SharedArrayBuffer")
6 | // needed in case process is undefined under Linux
7 | const platform = process.platform || os.platform()
8 |
9 | try {
10 | if (platform === 'win32' && nativeTheme.shouldUseDarkColors === true) {
11 | require('fs').unlinkSync(path.join(app.getPath('userData'), 'DevTools Extensions'))
12 | }
13 | } catch (_) {
14 | }
15 |
16 | let mainWindow
17 | const template = [
18 | {
19 | label: 'File',
20 | submenu: [
21 | {
22 | role: 'quit'
23 | }
24 | ]
25 | },
26 | {
27 | label: 'Edit',
28 | submenu: [
29 | {
30 | role: 'undo'
31 | },
32 | {
33 | role: 'redo'
34 | },
35 | {
36 | type: 'separator'
37 | },
38 | {
39 | role: 'cut'
40 | },
41 | {
42 | role: 'copy'
43 | },
44 | {
45 | role: 'paste'
46 | }
47 | ]
48 | },
49 |
50 | {
51 | label: 'View',
52 | submenu: [
53 | {
54 | role: 'reload'
55 | },
56 | {
57 | role: 'toggledevtools'
58 | },
59 | {
60 | type: 'separator'
61 | },
62 | {
63 | role: 'resetzoom'
64 | },
65 | {
66 | role: 'zoomin'
67 | },
68 | {
69 | role: 'zoomout'
70 | },
71 | {
72 | type: 'separator'
73 | },
74 | {
75 | role: 'togglefullscreen'
76 | }
77 | ]
78 | },
79 |
80 | {
81 | role: 'window',
82 | submenu: [
83 | {
84 | role: 'minimize'
85 | },
86 | {
87 | role: 'close'
88 | }
89 | ]
90 | },
91 | {
92 | role: 'help',
93 | submenu: [
94 | {
95 | label: 'About',
96 | role: 'about'
97 | },
98 | ]
99 | }
100 | ]
101 | function createWindow() {
102 | /**
103 | * Initial window options
104 | */
105 | mainWindow = new BrowserWindow({
106 | width: 1000,
107 | height: 600,
108 | useContentSize: true,
109 | autoHideMenuBar: false,
110 | icon: path.join(__dirname, 'icons/icon.ico'),
111 | webPreferences: {
112 | contextIsolation: true,
113 | // More info: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/electron-preload-script
114 | preload: path.resolve(__dirname, process.env.QUASAR_ELECTRON_PRELOAD)
115 | }
116 | })
117 |
118 | const menu = Menu.buildFromTemplate(template)
119 | Menu.setApplicationMenu(menu)
120 |
121 | mainWindow.loadURL(process.env.APP_URL)
122 | // mainWindow.webContents.openDevTools()
123 | mainWindow.webContents.closeDevTools()
124 | if (process.env.DEBUGGING) {
125 | // if on DEV or Production with debug enabled
126 | // mainWindow.webContents.closeDevTools()
127 | } else {
128 | // we're on production; no access to devtools pls
129 | mainWindow.webContents.on('devtools-opened', () => {
130 | //mainWindow.webContents.closeDevTools()
131 | })
132 | }
133 |
134 | mainWindow.on('closed', () => {
135 | mainWindow = null
136 | })
137 |
138 | }
139 |
140 | app.commandLine.appendSwitch('enable-experimental-web-platform-features');
141 | app.whenReady().then(createWindow)
142 |
143 | app.on('window-all-closed', () => {
144 | if (platform !== 'darwin') {
145 | app.quit()
146 | }
147 | })
148 |
149 | app.on('activate', () => {
150 | if (mainWindow === null) {
151 | createWindow()
152 | }
153 | })
154 |
--------------------------------------------------------------------------------
/src-electron/electron-preload.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is used specifically for security reasons.
3 | * Here you can access Nodejs stuff and inject functionality into
4 | * the renderer thread (accessible there through the "window" object)
5 | *
6 | * WARNING!
7 | * If you import anything from node_modules, then make sure that the package is specified
8 | * in package.json > dependencies and NOT in devDependencies
9 | *
10 | * Example (injects window.myAPI.doAThing() into renderer thread):
11 | *
12 | * import { contextBridge } from 'electron'
13 | *
14 | * contextBridge.exposeInMainWorld('myAPI', {
15 | * doAThing: () => {}
16 | * })
17 | */
18 |
--------------------------------------------------------------------------------
/src-electron/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src-electron/icon.png
--------------------------------------------------------------------------------
/src-electron/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src-electron/icons/icon.icns
--------------------------------------------------------------------------------
/src-electron/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src-electron/icons/icon.ico
--------------------------------------------------------------------------------
/src-electron/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src-electron/icons/icon.png
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
--------------------------------------------------------------------------------
/src/boot/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src/boot/.gitkeep
--------------------------------------------------------------------------------
/src/components/ReloadPrompt.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
37 |
38 |
39 | App ready to work offline
40 |
41 |
42 | New content available, click on reload button to update.
43 |
44 |
45 |
46 | Reload
47 |
48 |
49 | Close
50 |
51 |
52 |
53 |
54 |
80 |
--------------------------------------------------------------------------------
/src/components/help.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Help
6 |
7 |
8 |
9 |
10 | Settings Page:
11 |
12 |
13 | You need to create a free Mapbox account and enter your mapbox access token.
14 | Goto Mapbox then goto your account page. There you can
15 | copy
16 | your access token.
17 |
18 |
19 | Select a download folder. This is a folder on your local pc where your heightmap
20 | files will be saved.
21 |
22 |
23 |
24 | Map Page:
25 |
26 |
27 | Map Settings -- Enable different layers for viewing. This does not affect downloaded data
28 |
29 |
30 | Search Bar -- Enter the name of a location or Longitude Latitude seperated by a comma.
31 |
32 |
33 | Top Bar -- Area in KM show the area of the blue bounding box in Kilometers. Slippy Tile Info String
34 | is a standard
35 | format identification for downloading map tiles. Format is X,Y,Z Z = zoom level.
36 |
37 |
38 |
39 | Map Navigation:
40 |
41 |
42 |
43 | Select a Draw mode -- Select a draw mode from the control on the right of the map.
44 |
45 | Single tile select -- Select a single tile (default mode)
46 |
47 | Draw rectangle to select multiple tiles
48 | See Tile stitching video at the bottom for use.
49 |
50 |
51 | Left Mouse Click -- Selects a location on the map indicated by a blue bounding box.
52 |
53 |
54 | Double Left Mouse Click -- Download the tile preview and tile information.
55 |
56 |
57 | Left Mouse Hold -- Drag the mouse around to move the map.
58 |
59 |
60 | Left Mouse Hold -- Drag the mouse around to move the map.
61 |
62 |
63 | Right Mouse Hold -- Tilt and Rotate the map.
64 |
65 |
66 | Scroll Wheel -- Zoom in and out.
67 |
68 |
69 | Arrow Keys -- Move around the map.
70 |
71 |
72 |
73 | Left Side Bar:
74 |
75 |
Export Type:
76 |
77 |
78 | Unreal Heightmap -- Generates a 16-bit png heightmap file. Can be used in other applications
79 | besides Unreal.
80 |
81 |
82 | Unreal Terrain Magic Plugin -- EarthLandscape Clip -- Sends tile info string x,y and zoom to
83 | Terrain Magic.
84 | You will need to install the custom version of Terrain Magic from this link Custom Version Of
86 | Terrain Magic .
87 | Terrain magic has it's own map to import heightmaps for Unreal but I just added it to mine for ease of
88 | use.
89 | This just makes it a one click solution instead of copy and paste.
90 | If you like Terrain Magic please purchase it from the marketplace link in description. Original source
91 | for non-commercial Terrain
92 | Magic
93 |
94 |
95 | Unreal Terrain Magic Plugin -- HeightmapLandscape Clip -- Downloads heightmap from this app and
96 | loads it into Terrain Magic.
97 | You will need to install the custom version of Terrain Magic from this link Custom Version Of
99 | Terrain Magic .
100 | Terrain magic has it's own map to import heightmaps for Unreal but I just added to mine for ease of use.
101 | This just makes it a one click solution instead of copy and paste.
102 | If you like Terrain Magic please purchase it from the marketplace link in description. Original source
103 | for non-commercial Terrain
104 | Magic
105 |
106 |
107 | Unreal Stamp Brush Plugin -- You need to install paid plugin Landscape
109 | Stamping Tool - 100+ Custom Brushes .
110 | This automates the creation of new stamps from selected map location.
111 |
112 |
113 | Unreal Landmass Effect Brush Plugin -- Open source plugin for creating non-destructive landmass
114 | stamps and other features. Download the
115 | source from here SimplerLandmassBlueprints .
117 | From the Content folder copy the whole Editor folder to your Content directory. Each time you click Send
118 | To Unreal it will import
119 | the texture to a sub folder CustomBrushes > Textures. For now it only imports the texture you have to
120 | manually add the texture to
121 | the brush according to the github instructions.
122 |
123 |
124 | None -- Generate 16-bit png heightmap but do not do any other transformations to the image.
125 |
126 |
127 | Geojson Only -- Do not download a heightmap png file. Just download a Geojson file.
128 |
129 |
130 |
131 |
132 |
Export Options:
133 |
134 |
135 | Zrange-sea level= -- By checking this the imported heightmap will keep the landscape height near
136 | 100
137 | Unreal Units.
138 |
139 |
140 | FlipX/FlipY -- Flips the sides of the heightmap image in the X or Y direction.
141 |
142 |
143 | Download Satellite -- Downloads a Satellite Image of the selected area. This can be used as on
144 | overlay
145 | in UE.
146 |
147 |
148 | Download Geojson Features -- Downloads the features of the selected area in geojson format.
149 | Search
150 | Mapbox for geosjon.
151 |
152 |
153 | Combine Unique Features -- Removes overlapping features when downloading geojson
154 |
155 |
156 | Create Weightmap (Splatmap) Files -- You can now create weightmap files for use in Unreal for
157 | texturing your landscape.
158 | Setup and Use instructions https://www.youtube.com/watch?v=j_4pZ5EneVc&t=6s
159 |
160 |
161 |
162 |
163 |
164 | Landscape:
165 |
166 |
167 | Landscape Size -- Resamples the size of the image to recommended Unreal Landscape sizes.
168 |
169 |
170 | Enable World Partition -- If you have a World Partition project and want a World Partition
171 | landscape with proxies, enable this..
172 |
173 |
174 | World Partition Grid Size -- Grid size setting.
175 |
176 |
177 | Landscape Name -- Name of the landscape to be imported. (Optional
178 |
179 |
180 | Blur Radius -- Adds a gaussian blur to the heightmap png. This can help smooth out your imported
181 | landscape if it has some sharp edges. The greater the number the greater the blur. 0 = no blur.
182 |
183 |
184 |
185 |
186 | Buttons:
187 |
188 |
189 | Download Heightmap -- Downloads the heightmap png to the folder location on the settings page.
190 |
191 |
192 | Send To Unreal -- Automatically imports heightmap or stamp into your Unreal project. Required --
193 | Mapbox_BP has to be installed in to your unreal project and configured.
194 | You can download the free plugin here Unreal
195 | Mapbox Bridge Plugin .
196 |
197 |
198 | Copy Bounds for Blender OSM -- A plugin for blend that downloads real world map info into blender.
199 | It has it's own
200 | map but you can use this one as well since it has a search by name feature. Download Blender OSM .
202 |
203 |
204 | Copy Slippy Tile Info String -- This format is used in many other GIS applications to download map
205 | tile information. This is just
206 | a convenience function. This is also the same string Terrain Magic expects.
207 |
208 |
209 | Show Bounding Box Info -- General info such as Long/Lat info for bounding box.
210 |
211 |
212 |
213 |
214 |
221 |
222 |
223 | App Version {{ appVersion }}
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
283 |
--------------------------------------------------------------------------------
/src/components/maptiler-map-viewer.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Enable Layers
20 |
21 |
31 |
32 |
33 |
34 |
35 |
36 | {{ ' Zoom: ' + this.zoom + ' ' + this.tileInfoString }}
37 |
38 |
39 |
40 |
41 |
42 |
43 | Alert
44 |
45 |
46 |
47 | {{ alertMsg }}
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
659 |
660 |
661 |
--------------------------------------------------------------------------------
/src/components/wieghtmap-viewer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
84 |
85 |
93 |
--------------------------------------------------------------------------------
/src/css/app.scss:
--------------------------------------------------------------------------------
1 | // app global css in SCSS form
2 |
--------------------------------------------------------------------------------
/src/css/quasar.variables.scss:
--------------------------------------------------------------------------------
1 | // Quasar SCSS (& Sass) Variables
2 | // --------------------------------------------------
3 | // To customize the look and feel of this app, you can override
4 | // the Sass/SCSS variables found in Quasar's source Sass/SCSS files.
5 |
6 | // Check documentation for full list of Quasar variables
7 |
8 | // Your own variables (that are declared here) and Quasar's own
9 | // ones will be available out of the box in your .vue/.scss/.sass files
10 |
11 | // It's highly recommended to change the default colors
12 | // to match your app's branding.
13 | // Tip: Use the "Theme Builder" on Quasar's documentation website.
14 |
15 | $primary : #1976D2;
16 | $secondary : #26A69A;
17 | $accent : #9C27B0;
18 |
19 | $dark : #1D1D1D;
20 | $dark-page : #121212;
21 |
22 | $positive : #21BA45;
23 | $negative : #C10015;
24 | $info : #31CCEC;
25 | $warning : #F2C037;
26 |
--------------------------------------------------------------------------------
/src/css/styles.css:
--------------------------------------------------------------------------------
1 |
2 | /* // From: Pitch toggle control for Mapbox GL JS — http://fuzzytolerance.info/blog/2017/01/30/Pitch-toggle-control-for-Mapbox-GL-JS/ */
3 | .mapboxgl-ctrl-pitchtoggle-3d {
4 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCI+ICAgIDx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkeT0iLjM1ZW0iIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IGZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1hbmNob3I6IG1pZGRsZTsiPjNEPC90ZXh0Pjwvc3ZnPg==);
5 | }
6 |
7 | .mapboxgl-ctrl-pitchtoggle-2d {
8 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCI+ICAgIDx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkeT0iLjM1ZW0iIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IGZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1hbmNob3I6IG1pZGRsZTsiPjJEPC90ZXh0Pjwvc3ZnPg==);
9 | }
10 |
11 | /*
12 | // the images for mapbox-gl-draw_* are from
13 | https://github.com/mapbox/mapbox-gl-draw/blob/master/dist/mapbox-gl-draw.css
14 | */
15 | .mapbox-gl-draw_point {
16 | background-repeat: no-repeat;
17 | background-position: center;
18 | pointer-events: auto;
19 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJtYXJrZXIuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczE5MTY5IiAvPiAgPHNvZGlwb2RpOm5hbWVkdmlldyAgICAgaWQ9ImJhc2UiICAgICBwYWdlY29sb3I9IiNmZmZmZmYiICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIgICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6em9vbT0iMTYiICAgICBpbmtzY2FwZTpjeD0iMTQuMTY0MjUzIiAgICAgaW5rc2NhcGU6Y3k9IjguODg1NzIiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0iZmFsc2UiICAgICB1bml0cz0icHgiICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEyODAiICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3NTEiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMjA4IiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjE5MCIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpvYmplY3Qtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkMTk3MTUiIC8+ICA8L3NvZGlwb2RpOm5hbWVkdmlldz4gIDxtZXRhZGF0YSAgICAgaWQ9Im1ldGFkYXRhMTkxNzIiPiAgICA8cmRmOlJERj4gICAgICA8Y2M6V29yayAgICAgICAgIHJkZjphYm91dD0iIj4gICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PiAgICAgICAgPGRjOnR5cGUgICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+ICAgICAgICA8ZGM6dGl0bGUgLz4gICAgICA8L2NjOldvcms+ICAgIDwvcmRmOlJERj4gIDwvbWV0YWRhdGE+ICA8ZyAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiAgICAgaWQ9ImxheWVyMSIgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTEwMzIuMzYyMikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtjbGlwLXJ1bGU6bm9uemVybztkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjE7aXNvbGF0aW9uOmF1dG87bWl4LWJsZW5kLW1vZGU6bm9ybWFsO2NvbG9yLWludGVycG9sYXRpb246c1JHQjtjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6bGluZWFyUkdCO3NvbGlkLWNvbG9yOiMwMDAwMDA7c29saWQtb3BhY2l0eToxO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO2NvbG9yLXJlbmRlcmluZzphdXRvO2ltYWdlLXJlbmRlcmluZzphdXRvO3NoYXBlLXJlbmRlcmluZzphdXRvO3RleHQtcmVuZGVyaW5nOmF1dG87ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgICAgICAgZD0ibSAzNiwxMDQwLjM2MjIgYyA2ZS02LDMuMzA5MyAtNS45ODg2MTIsMTAgLTUuOTg4NjEyLDEwIDAsMCAtNS45OTg3NzYsLTYuNjY4IC02LjAxMTM0NSwtOS45NzcyIC0wLjAxMjU3LC0zLjMwOTIgMi42NTY1NzYsLTYuMDAzOSA1Ljk2NTc5MiwtNi4wMjI3IDMuMzA5MTg5LC0wLjAxOSA2LjAwODg0LDIuNjQ1MiA2LjAzMzk5Miw1Ljk1NDMiICAgICAgIGlkPSJwYXRoMTI1NjEiICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2Nzc2MiIC8+ICAgIDxwYXRoICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2NsaXAtcnVsZTpub256ZXJvO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MTtpc29sYXRpb246YXV0bzttaXgtYmxlbmQtbW9kZTpub3JtYWw7Y29sb3ItaW50ZXJwb2xhdGlvbjpzUkdCO2NvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpsaW5lYXJSR0I7c29saWQtY29sb3I6IzAwMDAwMDtzb2xpZC1vcGFjaXR5OjE7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7Y29sb3ItcmVuZGVyaW5nOmF1dG87aW1hZ2UtcmVuZGVyaW5nOmF1dG87c2hhcGUtcmVuZGVyaW5nOmF1dG87dGV4dC1yZW5kZXJpbmc6YXV0bztlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBkPSJtIDM0LjAwMDExNSwxMDQwLjM2MjIgYyAtNWUtNiwyLjIwNjIgLTMuOTkyNTIzLDcuMDAwMSAtMy45OTI1MjMsNy4wMDAxIDAsMCAtMy45OTkyOTEsLTQuNzc4NyAtNC4wMDc2NzksLTYuOTg0OSAtMC4wMDg0LC0yLjIwNjIgMS43NzEwODIsLTQuMDAyNyAzLjk3NzMxLC00LjAxNTMgMi4yMDYyMSwtMC4wMTMgNC4wMDYwMzcsMS43NjM1IDQuMDIyNzc3LDMuOTY5NyIgICAgICAgaWQ9InBhdGgxMjU2MyIgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NzYyIgLz4gICAgPHBhdGggICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7Y2xpcC1ydWxlOm5vbnplcm87ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7b3BhY2l0eToxO2lzb2xhdGlvbjphdXRvO21peC1ibGVuZC1tb2RlOm5vcm1hbDtjb2xvci1pbnRlcnBvbGF0aW9uOnNSR0I7Y29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOmxpbmVhclJHQjtzb2xpZC1jb2xvcjojMDAwMDAwO3NvbGlkLW9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtjb2xvci1yZW5kZXJpbmc6YXV0bztpbWFnZS1yZW5kZXJpbmc6YXV0bztzaGFwZS1yZW5kZXJpbmc6YXV0bzt0ZXh0LXJlbmRlcmluZzphdXRvO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGQ9Ik0gOS45NjY3OTY5LDEwMTQuMzYyMiBDIDYuNjU3NTgwOSwxMDE0LjM4MSAzLjk4NzQzLDEwMTcuMDc2NCA0LDEwMjAuMzg1NiBjIDAuMDEyNTY5LDMuMzA5MiA2LjAxMTcxOSw4Ljk3NjYgNi4wMTE3MTksOC45NzY2IDAsMCA1Ljk4ODI4NywtNS42OTA3IDUuOTg4MjgxLC05IGwgMCwtMC4wNDUgYyAtMC4wMjUxNSwtMy4zMDkxIC0yLjcyNDAxNCwtNS45NzQxIC02LjAzMzIwMzEsLTUuOTU1MSB6IG0gMC4wMDk3NywyIGMgMi4yMDYyMDYxLC0wLjAxMyA0LjAwNjY5MzEsMS43NjI2IDQuMDIzNDMzMSwzLjk2ODggbCAwLDAuMDMxIGMgLTVlLTYsMi4yMDYyIC0zLjk5MjE4OCw2IC0zLjk5MjE4OCw2IDAsMCAtMy45OTk0MjQsLTMuNzc4MiAtNC4wMDc4MTIsLTUuOTg0NCAtMC4wMDg0LC0yLjIwNjIgMS43NzAzMzQ1LC00LjAwMyAzLjk3NjU2MjUsLTQuMDE1NiB6IiAgICAgICBpZD0icGF0aDEyNTY4IiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzY3NjY2Njc2NzYyIgLz4gICAgPHBhdGggICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lIiAgICAgICBkPSJNIDEwIDIgQyA2LjY4NjI5MiAyIDQgNC42ODYzIDQgOCBDIDQgMTEuMzEzNyAxMCAxNyAxMCAxNyBDIDEwIDE3IDE2IDExLjMxMzcgMTYgOCBDIDE2IDQuNjg2MyAxMy4zMTM3MDggMiAxMCAyIHogTSAxMCA0IEMgMTIuMDcxMDY4IDQgMTMuNzUgNS42Nzg5IDEzLjc1IDcuNzUgQyAxMy43NSA5LjIwNTMyNzggMTEuOTMxMTEgMTEuNjQ0MzkzIDEwLjgzMDA3OCAxMyBMIDkuMTY5OTIxOSAxMyBDIDguMDY4ODkwMyAxMS42NDQzOTMgNi4yNSA5LjIwNTMyNzggNi4yNSA3Ljc1IEMgNi4yNSA1LjY3ODkgNy45Mjg5MzIgNCAxMCA0IHogIiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDEwMzIuMzYyMikiICAgICAgIGlkPSJwYXRoMTczMDUiIC8+ICA8L2c+PC9zdmc+);
20 | }
21 |
22 | .mapbox-gl-draw_line {
23 | background-repeat: no-repeat;
24 | background-position: center;
25 | pointer-events: auto;
26 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJsaW5lLnN2ZyI+ICA8ZGVmcyAgICAgaWQ9ImRlZnMxOTE2OSIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIGlkPSJiYXNlIiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiICAgICBib3JkZXJvcGFjaXR5PSIxLjAiICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOnpvb209IjE2IiAgICAgaW5rc2NhcGU6Y3g9IjEyLjg5ODc3NSIgICAgIGlua3NjYXBlOmN5PSI5LjU4OTAxNTIiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBkPSJtIDEzLjUsMTAzNS44NjIyIGMgLTEuMzgwNzEyLDAgLTIuNSwxLjExOTMgLTIuNSwyLjUgMCwwLjMyMDggMC4wNDYxNCwwLjYyNDQgMC4xNTYyNSwwLjkwNjMgbCAtMy43NSwzLjc1IGMgLTAuMjgxODM2LC0wLjExMDIgLTAuNTg1NDIxLC0wLjE1NjMgLTAuOTA2MjUsLTAuMTU2MyAtMS4zODA3MTIsMCAtMi41LDEuMTE5MyAtMi41LDIuNSAwLDEuMzgwNyAxLjExOTI4OCwyLjUgMi41LDIuNSAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTAuMzIwOCAtMC4wNDYxNCwtMC42MjQ0IC0wLjE1NjI1LC0wLjkwNjIgbCAzLjc1LC0zLjc1IGMgMC4yODE4MzYsMC4xMTAxIDAuNTg1NDIxLDAuMTU2MiAwLjkwNjI1LDAuMTU2MiAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTEuMzgwNyAtMS4xMTkyODgsLTIuNSAtMi41LC0yLjUgeiIgICAgICAgaWQ9InJlY3Q2NDY3IiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPiAgPC9nPjwvc3ZnPg==);
27 | }
28 |
29 | .mapbox-gl-draw_polygon {
30 | background-repeat: no-repeat;
31 | background-position: center;
32 | pointer-events: auto;
33 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJzcXVhcmUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczE5MTY5IiAvPiAgPHNvZGlwb2RpOm5hbWVkdmlldyAgICAgaWQ9ImJhc2UiICAgICBwYWdlY29sb3I9IiNmZmZmZmYiICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIgICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6em9vbT0iMTEuMzEzNzA4IiAgICAgaW5rc2NhcGU6Y3g9IjExLjY4MTYzNCIgICAgIGlua3NjYXBlOmN5PSI5LjI4NTcxNDMiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41O21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGQ9Im0gNSwxMDM5LjM2MjIgMCw2IDIsMiA2LDAgMiwtMiAwLC02IC0yLC0yIC02LDAgeiBtIDMsMCA0LDAgMSwxIDAsNCAtMSwxIC00LDAgLTEsLTEgMCwtNCB6IiAgICAgICBpZD0icmVjdDc3OTciICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjY2NjIiAvPiAgICA8Y2lyY2xlICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBpZD0icGF0aDQzNjQiICAgICAgIGN4PSI2IiAgICAgICBjeT0iMTA0Ni4zNjIyIiAgICAgICByPSIyIiAvPiAgICA8Y2lyY2xlICAgICAgIGlkPSJwYXRoNDM2OCIgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjYwMDAwMDAyO21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGN4PSIxNCIgICAgICAgY3k9IjEwNDYuMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBpZD0icGF0aDQzNzAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBjeD0iNiIgICAgICAgY3k9IjEwMzguMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuNjAwMDAwMDI7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgICAgICAgaWQ9InBhdGg0MzcyIiAgICAgICBjeD0iMTQiICAgICAgIGN5PSIxMDM4LjM2MjIiICAgICAgIHI9IjIiIC8+ICA8L2c+PC9zdmc+);
34 | }
35 |
36 | .highlight {
37 | background-color: green;
38 | }
39 |
--------------------------------------------------------------------------------
/src/layouts/MainLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
40 |
41 |
43 |
44 |
46 |
47 |
48 |
49 | mapserverChange(val)" v-model="mapserver" :options="servertype"
50 | label="Server Type"/>
51 |
52 |
53 | Maptiler Settings
54 |
55 |
60 |
61 |
66 |
67 |
68 |
74 |
75 |
80 |
81 |
87 |
88 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | Mapbox Settings
119 |
120 | See:
Mapbox access token
121 | docs
122 |
127 |
128 |
133 |
134 |
135 | See:
Mapbox style url
136 | docs
137 |
142 |
143 |
148 |
149 |
155 |
156 |
162 |
163 | Click
Copy
165 | Mapbox Weightmap Style
166 | to copy this style to your mapbox account and then paste your new style address in text box below in the
167 | format name/style id example: delebash/clfzz7dot000001qilz330eyt
168 |
174 |
175 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
198 |
199 |
200 |
201 |
203 |
204 |
205 |
206 |
207 |
221 |
222 |
223 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 | {{ props.row.name }}
233 |
234 |
235 |
236 |
237 |
238 | {{ props.row.color }}
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 | Alert
259 |
260 |
261 |
262 | {{ alertMsg }}
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
617 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2"]
3 | }
4 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/README.md:
--------------------------------------------------------------------------------
1 | ## Mapbox GL Draw Rectangle Assisted Mode
2 | [](https://badge.fury.io/js/%40geostarters%2Fmapbox-gl-draw-rectangle-assisted-mode)
3 |
4 | This is a custom mode for (Mapbox GL Draw) [https://github.com/mapbox/mapbox-gl-draw] that adds the functionality to draw assisted rectangles.
5 |
6 |
7 | 
8 |
9 | #### Changelog:
10 |
11 | ```bash
12 | Version 3.0.4: Change to Mapbox GL js v1.6.0 and fix minor dependencies
13 | Version 3.0.3: Change to Mapbox GL js v1.4.0
14 | Version 3.0.2: Add custom draw rectangle style
15 | Version 3.0.1: Add orientation angle calculation
16 | Version 3.0.0: Draw strict rentangle mode
17 | ```
18 | Based on:
19 |
20 | https://github.com/thegisdev/mapbox-gl-draw-rectangle-mode
21 |
22 | https://github.com/mapbox/mapbox-gl-draw/blob/master/src/modes/draw_polygon.js
23 |
24 |
25 | ### Install
26 |
27 | `npm install @geostarters/mapbox-gl-draw-rectangle-assisted-mode`
28 |
29 | ### Page Demo
30 |
31 | https://geostarters.github.io/mapbox-gl-draw-assisted-rectangle-mode/index.html
32 |
33 | ### Usage
34 |
35 | ```js
36 | import DrawRectangle from 'mapbox-gl-draw-rectangle-assisted-mode';
37 |
38 | mapboxgl.accessToken = '';
39 | const map = new mapboxgl.Map({
40 | container: 'map',
41 | style: 'https://tilemaps.icgc.cat/tileserver/styles/water.json',
42 | center: [-122.419518, 37.772995],
43 | zoom: 17,
44 | hash: true
45 | });
46 |
47 | const modes = MapboxDraw.modes;
48 | modes.draw_assisted_rectangle = DrawAssistedRectangle.default;
49 |
50 | const draw = new MapboxDraw({
51 | modes: modes,
52 | displayControlsDefault: false,
53 | controls: {
54 | polygon: true,
55 | trash: true
56 | },
57 | userProperties: true,
58 | styles: STYLES_DRAW
59 | });
60 | map.addControl(draw);
61 | map.on('draw.create', function (feature) {
62 | console.log(feature);
63 | });
64 |
65 | ```
66 |
67 |
68 |
69 | ### Build
70 |
71 | `npm build-web` with browsify
72 |
73 | `npm build-all` with babel
74 |
75 | ### License
76 |
77 | MIT
78 |
79 | ### Credits
80 |
81 | Developed by @ICGCAT
82 |
83 | More Info
84 | >[https://openicgc.github.io/](https://openicgc.github.io/)
85 |
86 | >[https://github.com/geostarters](https://github.com/geostarters)
87 |
88 | >[http://betaportal.icgc.cat/](http://betaportal.icgc.cat/)
89 |
90 | >[http://www.icgc.cat/en/](http://www.icgc.cat/en/)
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/dist/DrawAssistedRectangle.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var doubleClickZoom = {
8 | enable: function enable(ctx) {
9 | setTimeout(function () {
10 | // First check we've got a map and some context.
11 | if (!ctx.map || !ctx.map.doubleClickZoom || !ctx._ctx || !ctx._ctx.store || !ctx._ctx.store.getInitialConfigValue) return;
12 |
13 | if (!ctx._ctx.store.getInitialConfigValue("doubleClickZoom")) return;
14 | ctx.map.doubleClickZoom.enable();
15 | }, 0);
16 | },
17 | disable: function disable(ctx) {
18 | setTimeout(function () {
19 | if (!ctx.map || !ctx.map.doubleClickZoom) return;
20 |
21 | ctx.map.doubleClickZoom.disable();
22 | }, 0);
23 | }
24 | };
25 |
26 | var DrawAssistedRectangle = {
27 |
28 | onSetup: function onSetup(opts) {
29 | var rectangle = this.newFeature({
30 | type: "Feature",
31 | properties: {},
32 | geometry: {
33 | type: "Polygon",
34 | coordinates: [[]]
35 | }
36 | });
37 | this.addFeature(rectangle);
38 |
39 | this.clearSelectedFeatures();
40 | doubleClickZoom.disable(this);
41 | this.updateUIClasses({
42 | mouse: "add"
43 | });
44 | this.setActionableState({
45 | trash: true
46 | });
47 | return {
48 | rectangle: rectangle,
49 | currentVertexPosition: 0
50 | };
51 | },
52 |
53 | onTap: function onTap(state, e) {
54 |
55 | this.onClick(state, e);
56 | },
57 |
58 | onClick: function onClick(state, e) {
59 |
60 | if (state.currentVertexPosition === 2) {
61 |
62 | var getpXY3 = this.calculatepXY3(state, e, false);
63 |
64 | if (getpXY3) {
65 | state.rectangle.updateCoordinate("0." + (state.currentVertexPosition + 1), getpXY3[0], getpXY3[1]);
66 | }
67 | this.updateUIClasses({
68 | mouse: "pointer"
69 | });
70 | return this.changeMode("simple_select", {
71 | featuresId: state.rectangle.id
72 | });
73 | } else {
74 |
75 | state.rectangle.updateCoordinate("0." + state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
76 | state.currentVertexPosition++;
77 | state.rectangle.updateCoordinate("0." + state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
78 | }
79 | },
80 | onMouseMove: function onMouseMove(state, e) {
81 |
82 | state.rectangle.updateCoordinate("0." + state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
83 | if (state.currentVertexPosition && state.currentVertexPosition > 0) {
84 |
85 | this.calculateOrientedAnglePolygon(state);
86 | }
87 |
88 | if (state.currentVertexPosition === 2) {
89 | var getpXY3 = this.calculatepXY3(state, e, true);
90 | if (getpXY3) {
91 | state.rectangle.updateCoordinate("0." + (state.currentVertexPosition + 1), getpXY3[0], getpXY3[1]);
92 | }
93 | }
94 | },
95 |
96 | deegrees2meters: function deegrees2meters(px) {
97 |
98 | //gist from https://gist.github.com/springmeyer/871897
99 | var x = px[0] * 20037508.34 / 180;
100 | var y = Math.log(Math.tan((90 + px[1]) * Math.PI / 360)) / (Math.PI / 180);
101 | y = y * 20037508.34 / 180;
102 | return [x, y];
103 | },
104 | meters2degress: function meters2degress(px) {
105 | //gist from https://gist.github.com/springmeyer/871897
106 | var lon = px[0] * 180 / 20037508.34;
107 | var lat = Math.atan(Math.exp(px[1] * Math.PI / 20037508.34)) * 360 / Math.PI - 90;
108 | return [lon, lat];
109 | },
110 |
111 |
112 | calculateOrientedAnglePolygon: function calculateOrientedAnglePolygon(state) {
113 | var pXY0 = state.rectangle.getCoordinate("0.0");
114 | var pXY0_3857 = this.deegrees2meters(pXY0);
115 | var pXY1 = state.rectangle.getCoordinate("0.1");
116 | var pXY1_3857 = this.deegrees2meters(pXY1);
117 |
118 | var angleStdGraus = Math.atan2(pXY1_3857[1] - pXY0_3857[1], pXY1_3857[0] - pXY0_3857[0]) * 180 / Math.PI;
119 | var angleSudGraus = -1.0 * (angleStdGraus + 90);
120 | var angle = angleSudGraus < 0 ? angleSudGraus + 360 : angleSudGraus;
121 |
122 | state.angle = parseFloat(angle.toFixed(2));
123 | },
124 |
125 | calculatepXY3: function calculatepXY3(state, e, tmp) {
126 |
127 | var pXY0 = state.rectangle.getCoordinate("0.0");
128 | var pXY0_3857 = this.deegrees2meters(pXY0);
129 | var pXY1 = state.rectangle.getCoordinate("0.1");
130 | var pXY1_3857 = this.deegrees2meters(pXY1);
131 | var pXY2_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
132 | var mouse_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
133 |
134 | if (pXY0_3857[0] === pXY1_3857[0]) {
135 | pXY2_3857 = [mouse_3857[0], pXY1_3857[1]];
136 | } else if (pXY0_3857[1] === pXY1_3857[1]) {
137 | pXY2_3857 = [pXY1_3857[0], mouse_3857[1]];
138 | } else {
139 |
140 | var vector1_3857 = (pXY1_3857[1] - pXY0_3857[1]) / (pXY1_3857[0] - pXY0_3857[0]);
141 | var vector2_3857 = -1.0 / vector1_3857;
142 |
143 | if (Math.abs(vector2_3857) < 1) {
144 | pXY2_3857[1] = vector2_3857 * (mouse_3857[0] - pXY1_3857[0]) + pXY1_3857[1];
145 | } else {
146 | pXY2_3857[0] = pXY1_3857[0] + (pXY2_3857[1] - pXY1_3857[1]) / vector2_3857;
147 | }
148 | }
149 |
150 | var vector_3857 = [pXY1_3857[0] - pXY0_3857[0], pXY1_3857[1] - pXY0_3857[1]];
151 | var pXY3_3857 = [pXY2_3857[0] - vector_3857[0], pXY2_3857[1] - vector_3857[1]];
152 | var pXY2G = this.meters2degress(pXY2_3857);
153 | var pXY3G = this.meters2degress(pXY3_3857);
154 | state.rectangle.updateCoordinate("0.2", pXY2G[0], pXY2G[1]);
155 | state.rectangle.updateCoordinate("0.3", pXY3G[0], pXY3G[1]);
156 |
157 | return pXY3G;
158 | },
159 |
160 | onKeyUp: function onKeyUp(state, e) {
161 | if (e.keyCode === 27) return this.changeMode("simple_select");
162 | },
163 | onStop: function onStop(state) {
164 | doubleClickZoom.enable(this);
165 | this.updateUIClasses({
166 | mouse: "none"
167 | });
168 | this.activateUIButton();
169 |
170 | // check to see if we've deleted this feature
171 | if (this.getFeature(state.rectangle.id) === undefined) return;
172 |
173 | //remove last added coordinate
174 | state.rectangle.removeCoordinate("0.4");
175 | if (state.rectangle.isValid()) {
176 | this.map.fire("draw.create", {
177 | features: [state.rectangle.toGeoJSON()]
178 | });
179 | } else {
180 | this.deleteFeature([state.rectangle.id], {
181 | silent: true
182 | });
183 | this.changeMode("simple_select", {}, {
184 | silent: true
185 | });
186 | }
187 | },
188 | toDisplayFeatures: function toDisplayFeatures(state, geojson, display) {
189 | var isActivePolygon = geojson.properties.id === state.rectangle.id;
190 | geojson.properties.active = isActivePolygon ? "true" : "false";
191 | geojson.properties.angle = state.angle;
192 | geojson.angle = state.angle;
193 | if (!isActivePolygon) return display(geojson);
194 |
195 | var coordinateCount = geojson.geometry.coordinates[0].length;
196 |
197 | if (coordinateCount < 3) {
198 |
199 | var coordinates = geojson.geometry.coordinates[0][0];
200 |
201 | var vertexPoint = {
202 | type: "Feature",
203 | properties: geojson.properties,
204 | angle: state.angle,
205 | geometry: {
206 | coordinates: geojson.geometry.coordinates[0][0],
207 | type: "Point"
208 | }
209 | };
210 |
211 | if (coordinates) {
212 | display(vertexPoint);
213 | }
214 |
215 | return;
216 | }
217 | if (coordinateCount >= 3 && coordinateCount <= 4) {
218 |
219 | var lineCoordinates = [[geojson.geometry.coordinates[0][0][0], geojson.geometry.coordinates[0][0][1]], [geojson.geometry.coordinates[0][1][0], geojson.geometry.coordinates[0][1][1]]];
220 |
221 | display({
222 | type: "Feature",
223 | properties: geojson.properties,
224 | angle: state.angle,
225 | geometry: {
226 | coordinates: lineCoordinates,
227 | type: "LineString"
228 | }
229 | });
230 | if (coordinateCount === 3) {
231 | return;
232 | }
233 | }
234 |
235 | return display(geojson);
236 | },
237 | onTrash: function onTrash(state) {
238 | this.deleteFeature([state.rectangle.id], {
239 | silent: true
240 | });
241 | this.changeMode("simple_select");
242 | }
243 | };
244 |
245 | exports.default = DrawAssistedRectangle;
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/dist/DrawAssistedRectangle.min.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.DrawAssistedRectangle = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) {
85 |
86 | this.calculateOrientedAnglePolygon(state);
87 | }
88 |
89 | if (state.currentVertexPosition === 2) {
90 | var getpXY3 = this.calculatepXY3(state, e, true);
91 | if (getpXY3) {
92 | state.rectangle.updateCoordinate("0." + (state.currentVertexPosition + 1), getpXY3[0], getpXY3[1]);
93 | }
94 | }
95 | },
96 |
97 | deegrees2meters: function deegrees2meters(px) {
98 |
99 | //gist from https://gist.github.com/springmeyer/871897
100 | var x = px[0] * 20037508.34 / 180;
101 | var y = Math.log(Math.tan((90 + px[1]) * Math.PI / 360)) / (Math.PI / 180);
102 | y = y * 20037508.34 / 180;
103 | return [x, y];
104 | },
105 | meters2degress: function meters2degress(px) {
106 | //gist from https://gist.github.com/springmeyer/871897
107 | var lon = px[0] * 180 / 20037508.34;
108 | var lat = Math.atan(Math.exp(px[1] * Math.PI / 20037508.34)) * 360 / Math.PI - 90;
109 | return [lon, lat];
110 | },
111 |
112 |
113 | calculateOrientedAnglePolygon: function calculateOrientedAnglePolygon(state) {
114 | var pXY0 = state.rectangle.getCoordinate("0.0");
115 | var pXY0_3857 = this.deegrees2meters(pXY0);
116 | var pXY1 = state.rectangle.getCoordinate("0.1");
117 | var pXY1_3857 = this.deegrees2meters(pXY1);
118 |
119 | var angleStdGraus = Math.atan2(pXY1_3857[1] - pXY0_3857[1], pXY1_3857[0] - pXY0_3857[0]) * 180 / Math.PI;
120 | var angleSudGraus = -1.0 * (angleStdGraus + 90);
121 | var angle = angleSudGraus < 0 ? angleSudGraus + 360 : angleSudGraus;
122 |
123 | state.angle = parseFloat(angle.toFixed(2));
124 | },
125 |
126 | calculatepXY3: function calculatepXY3(state, e, tmp) {
127 |
128 | var pXY0 = state.rectangle.getCoordinate("0.0");
129 | var pXY0_3857 = this.deegrees2meters(pXY0);
130 | var pXY1 = state.rectangle.getCoordinate("0.1");
131 | var pXY1_3857 = this.deegrees2meters(pXY1);
132 | var pXY2_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
133 | var mouse_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
134 |
135 | if (pXY0_3857[0] === pXY1_3857[0]) {
136 | pXY2_3857 = [mouse_3857[0], pXY1_3857[1]];
137 | } else if (pXY0_3857[1] === pXY1_3857[1]) {
138 | pXY2_3857 = [pXY1_3857[0], mouse_3857[1]];
139 | } else {
140 |
141 | var vector1_3857 = (pXY1_3857[1] - pXY0_3857[1]) / (pXY1_3857[0] - pXY0_3857[0]);
142 | var vector2_3857 = -1.0 / vector1_3857;
143 |
144 | if (Math.abs(vector2_3857) < 1) {
145 | pXY2_3857[1] = vector2_3857 * (mouse_3857[0] - pXY1_3857[0]) + pXY1_3857[1];
146 | } else {
147 | pXY2_3857[0] = pXY1_3857[0] + (pXY2_3857[1] - pXY1_3857[1]) / vector2_3857;
148 | }
149 | }
150 |
151 | var vector_3857 = [pXY1_3857[0] - pXY0_3857[0], pXY1_3857[1] - pXY0_3857[1]];
152 | var pXY3_3857 = [pXY2_3857[0] - vector_3857[0], pXY2_3857[1] - vector_3857[1]];
153 | var pXY2G = this.meters2degress(pXY2_3857);
154 | var pXY3G = this.meters2degress(pXY3_3857);
155 | state.rectangle.updateCoordinate("0.2", pXY2G[0], pXY2G[1]);
156 | state.rectangle.updateCoordinate("0.3", pXY3G[0], pXY3G[1]);
157 |
158 | return pXY3G;
159 | },
160 |
161 | onKeyUp: function onKeyUp(state, e) {
162 | if (e.keyCode === 27) return this.changeMode("simple_select");
163 | },
164 | onStop: function onStop(state) {
165 | doubleClickZoom.enable(this);
166 | this.updateUIClasses({
167 | mouse: "none"
168 | });
169 | this.activateUIButton();
170 |
171 | // check to see if we've deleted this feature
172 | if (this.getFeature(state.rectangle.id) === undefined) return;
173 |
174 | //remove last added coordinate
175 | state.rectangle.removeCoordinate("0.4");
176 | if (state.rectangle.isValid()) {
177 | this.map.fire("draw.create", {
178 | features: [state.rectangle.toGeoJSON()]
179 | });
180 | } else {
181 | this.deleteFeature([state.rectangle.id], {
182 | silent: true
183 | });
184 | this.changeMode("simple_select", {}, {
185 | silent: true
186 | });
187 | }
188 | },
189 | toDisplayFeatures: function toDisplayFeatures(state, geojson, display) {
190 | var isActivePolygon = geojson.properties.id === state.rectangle.id;
191 | geojson.properties.active = isActivePolygon ? "true" : "false";
192 | geojson.properties.angle = state.angle;
193 | geojson.angle = state.angle;
194 | if (!isActivePolygon) return display(geojson);
195 |
196 | var coordinateCount = geojson.geometry.coordinates[0].length;
197 |
198 | if (coordinateCount < 3) {
199 |
200 | var coordinates = geojson.geometry.coordinates[0][0];
201 |
202 | var vertexPoint = {
203 | type: "Feature",
204 | properties: geojson.properties,
205 | angle: state.angle,
206 | geometry: {
207 | coordinates: geojson.geometry.coordinates[0][0],
208 | type: "Point"
209 | }
210 | };
211 |
212 | if (coordinates) {
213 | display(vertexPoint);
214 | }
215 |
216 | return;
217 | }
218 | if (coordinateCount >= 3 && coordinateCount <= 4) {
219 |
220 | var lineCoordinates = [[geojson.geometry.coordinates[0][0][0], geojson.geometry.coordinates[0][0][1]], [geojson.geometry.coordinates[0][1][0], geojson.geometry.coordinates[0][1][1]]];
221 |
222 | display({
223 | type: "Feature",
224 | properties: geojson.properties,
225 | angle: state.angle,
226 | geometry: {
227 | coordinates: lineCoordinates,
228 | type: "LineString"
229 | }
230 | });
231 | if (coordinateCount === 3) {
232 | return;
233 | }
234 | }
235 |
236 | return display(geojson);
237 | },
238 | onTrash: function onTrash(state) {
239 | this.deleteFeature([state.rectangle.id], {
240 | silent: true
241 | });
242 | this.changeMode("simple_select");
243 | }
244 | };
245 |
246 | exports.default = DrawAssistedRectangle;
247 | },{}]},{},[1])(1)
248 | });
249 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/draw-assisted-rectangle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src/mapbox-gl-draw-assisted-rectangle-mode/draw-assisted-rectangle.gif
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Mapbox GL Draw Assisted Rectangle
8 |
9 |
10 |
11 |
12 |
14 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
202 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@geostarters/mapbox-gl-draw-rectangle-assisted-mode",
3 | "version": "3.0.4",
4 | "description": "A custom mode for MapboxGL Draw to draw a assisted rentangle",
5 | "main": "dist/DrawAssistedRectangle.js",
6 | "author": "Geostarters - ICGC",
7 | "license": "MIT",
8 | "repository": "https://github.com/geostarters/mapbox-gl-draw-assisted-rectangle-mode",
9 | "keywords": [
10 | "MapBox GL",
11 | "Mapbox-gl-Draw",
12 | "Custom mode",
13 | "Assisted Rectangle",
14 | "Vector Tiles"
15 | ],
16 | "scripts": {
17 | "build": "babel src -d dist",
18 | "build-web": "browserify dist/DrawAssistedRectangle.js --standalone DrawAssistedRectangle --outfile dist/DrawAssistedRectangle.min.js",
19 | "build-all": "run-s build build-web"
20 | },
21 | "devDependencies": {
22 | "babel": "^6.23.0",
23 | "babel-cli": "^6.26.0",
24 | "babel-core": "^6.25.0",
25 | "babel-preset-es2015": "^6.24.1",
26 | "babel-preset-stage-2": "^6.24.1",
27 | "npm-run-all": "^4.1.2"
28 | },
29 | "dependencies": {
30 | "@babel/plugin-transform-modules-commonjs": "^7.6.0",
31 | "browserify": "^16.5.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/mapbox-gl-draw-assisted-rectangle-mode/src/DrawAssistedRectangle.js:
--------------------------------------------------------------------------------
1 |
2 | const doubleClickZoom = {
3 | enable: ctx => {
4 | setTimeout(() => {
5 | // First check we've got a map and some context.
6 | if (
7 | !ctx.map ||
8 | !ctx.map.doubleClickZoom ||
9 | !ctx._ctx ||
10 | !ctx._ctx.store ||
11 | !ctx._ctx.store.getInitialConfigValue
12 | )
13 | return;
14 |
15 | if (!ctx._ctx.store.getInitialConfigValue("doubleClickZoom")) return;
16 | ctx.map.doubleClickZoom.enable();
17 | }, 0);
18 | },
19 | disable(ctx) {
20 | setTimeout(() => {
21 | if (!ctx.map || !ctx.map.doubleClickZoom) return;
22 |
23 | ctx.map.doubleClickZoom.disable();
24 | }, 0);
25 | }
26 | };
27 |
28 | const DrawAssistedRectangle = {
29 |
30 | onSetup: function (opts) {
31 | const rectangle = this.newFeature({
32 | type: "Feature",
33 | properties: {},
34 | geometry: {
35 | type: "Polygon",
36 | coordinates: [
37 | []
38 | ]
39 | }
40 | });
41 | this.addFeature(rectangle);
42 |
43 | this.clearSelectedFeatures();
44 | doubleClickZoom.disable(this);
45 | this.updateUIClasses({
46 | mouse: "add"
47 | });
48 | this.setActionableState({
49 | trash: true
50 | });
51 | return {
52 | rectangle,
53 | currentVertexPosition: 0
54 | };
55 | },
56 |
57 | onTap: function (state, e) {
58 |
59 | this.onClick(state, e);
60 | },
61 |
62 | onClick: function (state, e) {
63 |
64 | if (state.currentVertexPosition === 2) {
65 |
66 | const getpXY3 = this.calculatepXY3(state, e, false);
67 |
68 | if (getpXY3) {
69 | state.rectangle.updateCoordinate(`0.${state.currentVertexPosition + 1}`, getpXY3[0], getpXY3[1]);
70 | }
71 | this.updateUIClasses({
72 | mouse: "pointer"
73 | });
74 | return this.changeMode("simple_select", {
75 | featuresId: state.rectangle.id
76 | });
77 |
78 |
79 | } else {
80 |
81 | state.rectangle.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat);
82 | state.currentVertexPosition++;
83 | state.rectangle.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat);
84 |
85 | }
86 |
87 |
88 | },
89 | onMouseMove: function (state, e) {
90 |
91 | state.rectangle.updateCoordinate("0." + state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat);
92 | if (state.currentVertexPosition && state.currentVertexPosition > 0) {
93 |
94 | this.calculateOrientedAnglePolygon(state);
95 |
96 | }
97 |
98 | if (state.currentVertexPosition === 2) {
99 | const getpXY3 = this.calculatepXY3(state, e, true);
100 |
101 | if (getpXY3) {
102 | state.rectangle.updateCoordinate("0." + (state.currentVertexPosition + 1), getpXY3[0], getpXY3[1]);
103 | }
104 | }
105 |
106 | },
107 |
108 |
109 |
110 |
111 | deegrees2meters(px) {
112 |
113 | //gist from https://gist.github.com/springmeyer/871897
114 | const x = px[0] * 20037508.34 / 180;
115 | let y = Math.log(Math.tan((90 + px[1]) * Math.PI / 360)) / (Math.PI / 180);
116 | y = y * 20037508.34 / 180;
117 | return [x, y]
118 |
119 | },
120 |
121 | meters2degress(px) {
122 | //gist from https://gist.github.com/springmeyer/871897
123 | const lon = px[0] * 180 / 20037508.34;
124 | const lat = Math.atan(Math.exp(px[1] * Math.PI / 20037508.34)) * 360 / Math.PI - 90;
125 | return [lon, lat]
126 | },
127 |
128 | calculateOrientedAnglePolygon: function (state) {
129 | const pXY0 = state.rectangle.getCoordinate("0.0");
130 | const pXY0_3857 = this.deegrees2meters(pXY0);
131 | const pXY1 = state.rectangle.getCoordinate("0.1");
132 | const pXY1_3857 = this.deegrees2meters(pXY1);
133 | const angleStdGraus = Math.atan2(pXY1_3857[1] - pXY0_3857[1], pXY1_3857[0] - pXY0_3857[0]) * 180 / Math.PI;
134 |
135 | let angleSudGraus = -1.0 * (angleStdGraus + 90);
136 | const angle = angleSudGraus < 0 ? angleSudGraus + 360 : angleSudGraus;
137 |
138 | state.angle = parseFloat((angle).toFixed(2));
139 |
140 | },
141 |
142 | calculatepXY3: function (state, e, tmp) {
143 |
144 | const pXY0 = state.rectangle.getCoordinate("0.0");
145 | const pXY0_3857 = this.deegrees2meters(pXY0);
146 | const pXY1 = state.rectangle.getCoordinate("0.1");
147 | const pXY1_3857 = this.deegrees2meters(pXY1);
148 | let pXY2_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
149 | const mouse_3857 = this.deegrees2meters([e.lngLat.lng, e.lngLat.lat]);
150 |
151 | if (pXY0_3857[0] === pXY1_3857[0]) {
152 | pXY2_3857 = [mouse_3857[0], pXY1_3857[1]];
153 | } else if (pXY0_3857[1] === pXY1_3857[1]) {
154 | pXY2_3857 = [pXY1_3857[0], mouse_3857[1]];
155 |
156 | } else {
157 |
158 | const vector1_3857 = (pXY1_3857[1] - pXY0_3857[1]) / (pXY1_3857[0] - pXY0_3857[0]);
159 | const vector2_3857 = -1.0 / vector1_3857;
160 |
161 | if (Math.abs(vector2_3857) < 1) {
162 | pXY2_3857[1] = vector2_3857 * (mouse_3857[0] - pXY1_3857[0]) + pXY1_3857[1];
163 | }
164 | else {
165 | pXY2_3857[0] = pXY1_3857[0] + (pXY2_3857[1] - pXY1_3857[1]) / vector2_3857;
166 | }
167 |
168 |
169 | }
170 |
171 | const vector_3857 = [pXY1_3857[0] - pXY0_3857[0], pXY1_3857[1] - pXY0_3857[1]];
172 | const pXY3_3857 = [pXY2_3857[0] - vector_3857[0], pXY2_3857[1] - vector_3857[1]];
173 | const pXY2G = this.meters2degress(pXY2_3857);
174 | const pXY3G = this.meters2degress(pXY3_3857);
175 | state.rectangle.updateCoordinate("0.2", pXY2G[0], pXY2G[1]);
176 | state.rectangle.updateCoordinate("0.3", pXY3G[0], pXY3G[1]);
177 |
178 | return pXY3G;
179 |
180 | },
181 |
182 |
183 | onKeyUp: function (state, e) {
184 | if (e.keyCode === 27) return this.changeMode("simple_select");
185 | },
186 | onStop: function (state) {
187 | doubleClickZoom.enable(this);
188 | this.updateUIClasses({
189 | mouse: "none"
190 | });
191 | this.activateUIButton();
192 |
193 | // check to see if we've deleted this feature
194 | if (this.getFeature(state.rectangle.id) === undefined) return;
195 |
196 | //remove last added coordinate
197 | state.rectangle.removeCoordinate("0.4");
198 | if (state.rectangle.isValid()) {
199 | this.map.fire("draw.create", {
200 | features: [state.rectangle.toGeoJSON()]
201 | });
202 | } else {
203 | this.deleteFeature([state.rectangle.id], {
204 | silent: true
205 | });
206 | this.changeMode("simple_select", {}, {
207 | silent: true
208 | });
209 | }
210 | },
211 | toDisplayFeatures: function (state, geojson, display) {
212 | const isActivePolygon = geojson.properties.id === state.rectangle.id;
213 | geojson.properties.active = isActivePolygon ? "true" : "false";
214 | geojson.properties.angle = state.angle;
215 | geojson.angle = state.angle;
216 | if (!isActivePolygon) return display(geojson);
217 |
218 | const coordinateCount = geojson.geometry.coordinates[0].length;
219 |
220 | if (coordinateCount < 3) {
221 |
222 | const coordinates = geojson.geometry.coordinates[0][0];
223 |
224 | const vertexPoint = {
225 | type: "Feature",
226 | properties: geojson.properties,
227 | angle: state.angle,
228 | geometry: {
229 | coordinates: geojson.geometry.coordinates[0][0],
230 | type: "Point"
231 | }
232 | };
233 |
234 | if (coordinates) {
235 | display(vertexPoint);
236 | }
237 |
238 |
239 | return;
240 | }
241 | if (coordinateCount >= 3 && coordinateCount <= 4) {
242 |
243 | const lineCoordinates = [
244 | [geojson.geometry.coordinates[0][0][0], geojson.geometry.coordinates[0][0][1]],
245 | [geojson.geometry.coordinates[0][1][0], geojson.geometry.coordinates[0][1][1]]
246 | ];
247 |
248 | display({
249 | type: "Feature",
250 | properties: geojson.properties,
251 | angle: state.angle,
252 | geometry: {
253 | coordinates: lineCoordinates,
254 | type: "LineString"
255 | }
256 | });
257 | if (coordinateCount === 3) {
258 | return;
259 | }
260 | }
261 |
262 | return display(geojson);
263 | },
264 | onTrash: function (state) {
265 | this.deleteFeature([state.rectangle.id], {
266 | silent: true
267 | });
268 | this.changeMode("simple_select");
269 | }
270 | };
271 |
272 | export default DrawAssistedRectangle;
273 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/.ignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/Example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Mapbox Add Control
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/Example/index.js:
--------------------------------------------------------------------------------
1 | import mapboxgl from 'mapbox-gl';
2 | import 'mapbox-gl/dist/mapbox-gl.css'
3 | import './styles.css'
4 | import MapboxGLButtonControl from '@delebash/mapbox-gl-button-control'
5 |
6 | mapboxgl.accessToken =
7 | "your mapbox access token";
8 |
9 | let map = new mapboxgl.Map({
10 | container: "map", // container id
11 | style: "mapbox://styles/mapbox/streets-v9", // stylesheet location
12 | center: [-64.75, 32.3], // starting position [lng, lat]
13 | zoom: 10 // starting zoom
14 | });
15 |
16 | /* Event Handlers */
17 | function one(event) {
18 | alert("Event handler when clicking on \r\n" + event.target.className);
19 | console.log("event number 1", event);
20 | }
21 |
22 | function two(event) {
23 | alert("Event handler when clicking on \r\n" + event.target.className);
24 | console.log("event number 2", event);
25 | }
26 |
27 | function three(event) {
28 | alert("Event handler when clicking on \r\n" + event.target.className);
29 | console.log("event number 3", event);
30 | }
31 |
32 | /* Instantiate new controls with custom event handlers */
33 | const ctrlPoint = new MapboxGLButtonControl({
34 | className: "mapbox-gl-draw_point",
35 | title: "Draw Point",
36 | eventHandler: one
37 | });
38 |
39 | const ctrlLine = new MapboxGLButtonControl({
40 | className: "mapbox-gl-draw_line",
41 | title: "Draw Line",
42 | eventHandler: two
43 | });
44 |
45 | const ctrlPolygon = new MapboxGLButtonControl({
46 | className: "mapbox-gl-draw_polygon",
47 | title: "Draw Polygon",
48 | eventHandler: three
49 | });
50 |
51 | /* Add Controls to the Map */
52 | map.addControl(new mapboxgl.NavigationControl(), "top-left");
53 | map.addControl(ctrlPoint, "bottom-left");
54 | map.addControl(ctrlLine, "bottom-right");
55 | map.addControl(ctrlPolygon, "top-right");
56 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/Example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-project",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "start": "vite",
7 | "build": "vite build",
8 | "preview": "vite preview"
9 | },
10 | "devDependencies": {
11 | "vite": "^3.1.0"
12 | },
13 | "dependencies": {
14 | "@delebash/mapbox-gl-button-control": "^1.0.3",
15 | "mapbox-gl": "^2.10.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/Example/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | #map {
7 | position: absolute;
8 | top: 0;
9 | bottom: 0;
10 | width: 100%;
11 | }
12 |
13 | /* // From: Pitch toggle control for Mapbox GL JS — http://fuzzytolerance.info/blog/2017/01/30/Pitch-toggle-control-for-Mapbox-GL-JS/ */
14 | .mapboxgl-ctrl-pitchtoggle-3d {
15 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCI+ICAgIDx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkeT0iLjM1ZW0iIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IGZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1hbmNob3I6IG1pZGRsZTsiPjNEPC90ZXh0Pjwvc3ZnPg==);
16 | }
17 |
18 | .mapboxgl-ctrl-pitchtoggle-2d {
19 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCI+ICAgIDx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkeT0iLjM1ZW0iIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IGZvbnQtZmFtaWx5OiAnSGVsdmV0aWNhIE5ldWUnLEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1hbmNob3I6IG1pZGRsZTsiPjJEPC90ZXh0Pjwvc3ZnPg==);
20 | }
21 |
22 | /*
23 | // the images for mapbox-gl-draw_* are from
24 | https://github.com/mapbox/mapbox-gl-draw/blob/master/dist/mapbox-gl-draw.css
25 | */
26 | .mapbox-gl-draw_point {
27 | background-repeat: no-repeat;
28 | background-position: center;
29 | pointer-events: auto;
30 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJtYXJrZXIuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczE5MTY5IiAvPiAgPHNvZGlwb2RpOm5hbWVkdmlldyAgICAgaWQ9ImJhc2UiICAgICBwYWdlY29sb3I9IiNmZmZmZmYiICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIgICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6em9vbT0iMTYiICAgICBpbmtzY2FwZTpjeD0iMTQuMTY0MjUzIiAgICAgaW5rc2NhcGU6Y3k9IjguODg1NzIiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0iZmFsc2UiICAgICB1bml0cz0icHgiICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEyODAiICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3NTEiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMjA4IiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjE5MCIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpvYmplY3Qtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkMTk3MTUiIC8+ICA8L3NvZGlwb2RpOm5hbWVkdmlldz4gIDxtZXRhZGF0YSAgICAgaWQ9Im1ldGFkYXRhMTkxNzIiPiAgICA8cmRmOlJERj4gICAgICA8Y2M6V29yayAgICAgICAgIHJkZjphYm91dD0iIj4gICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PiAgICAgICAgPGRjOnR5cGUgICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+ICAgICAgICA8ZGM6dGl0bGUgLz4gICAgICA8L2NjOldvcms+ICAgIDwvcmRmOlJERj4gIDwvbWV0YWRhdGE+ICA8ZyAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiAgICAgaWQ9ImxheWVyMSIgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTEwMzIuMzYyMikiPiAgICA8cGF0aCAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtjbGlwLXJ1bGU6bm9uemVybztkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjE7aXNvbGF0aW9uOmF1dG87bWl4LWJsZW5kLW1vZGU6bm9ybWFsO2NvbG9yLWludGVycG9sYXRpb246c1JHQjtjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6bGluZWFyUkdCO3NvbGlkLWNvbG9yOiMwMDAwMDA7c29saWQtb3BhY2l0eToxO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO2NvbG9yLXJlbmRlcmluZzphdXRvO2ltYWdlLXJlbmRlcmluZzphdXRvO3NoYXBlLXJlbmRlcmluZzphdXRvO3RleHQtcmVuZGVyaW5nOmF1dG87ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgICAgICAgZD0ibSAzNiwxMDQwLjM2MjIgYyA2ZS02LDMuMzA5MyAtNS45ODg2MTIsMTAgLTUuOTg4NjEyLDEwIDAsMCAtNS45OTg3NzYsLTYuNjY4IC02LjAxMTM0NSwtOS45NzcyIC0wLjAxMjU3LC0zLjMwOTIgMi42NTY1NzYsLTYuMDAzOSA1Ljk2NTc5MiwtNi4wMjI3IDMuMzA5MTg5LC0wLjAxOSA2LjAwODg0LDIuNjQ1MiA2LjAzMzk5Miw1Ljk1NDMiICAgICAgIGlkPSJwYXRoMTI1NjEiICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2Nzc2MiIC8+ICAgIDxwYXRoICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2NsaXAtcnVsZTpub256ZXJvO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MTtpc29sYXRpb246YXV0bzttaXgtYmxlbmQtbW9kZTpub3JtYWw7Y29sb3ItaW50ZXJwb2xhdGlvbjpzUkdCO2NvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpsaW5lYXJSR0I7c29saWQtY29sb3I6IzAwMDAwMDtzb2xpZC1vcGFjaXR5OjE7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7Y29sb3ItcmVuZGVyaW5nOmF1dG87aW1hZ2UtcmVuZGVyaW5nOmF1dG87c2hhcGUtcmVuZGVyaW5nOmF1dG87dGV4dC1yZW5kZXJpbmc6YXV0bztlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBkPSJtIDM0LjAwMDExNSwxMDQwLjM2MjIgYyAtNWUtNiwyLjIwNjIgLTMuOTkyNTIzLDcuMDAwMSAtMy45OTI1MjMsNy4wMDAxIDAsMCAtMy45OTkyOTEsLTQuNzc4NyAtNC4wMDc2NzksLTYuOTg0OSAtMC4wMDg0LC0yLjIwNjIgMS43NzEwODIsLTQuMDAyNyAzLjk3NzMxLC00LjAxNTMgMi4yMDYyMSwtMC4wMTMgNC4wMDYwMzcsMS43NjM1IDQuMDIyNzc3LDMuOTY5NyIgICAgICAgaWQ9InBhdGgxMjU2MyIgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NzYyIgLz4gICAgPHBhdGggICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7Y2xpcC1ydWxlOm5vbnplcm87ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7b3BhY2l0eToxO2lzb2xhdGlvbjphdXRvO21peC1ibGVuZC1tb2RlOm5vcm1hbDtjb2xvci1pbnRlcnBvbGF0aW9uOnNSR0I7Y29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOmxpbmVhclJHQjtzb2xpZC1jb2xvcjojMDAwMDAwO3NvbGlkLW9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtjb2xvci1yZW5kZXJpbmc6YXV0bztpbWFnZS1yZW5kZXJpbmc6YXV0bztzaGFwZS1yZW5kZXJpbmc6YXV0bzt0ZXh0LXJlbmRlcmluZzphdXRvO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGQ9Ik0gOS45NjY3OTY5LDEwMTQuMzYyMiBDIDYuNjU3NTgwOSwxMDE0LjM4MSAzLjk4NzQzLDEwMTcuMDc2NCA0LDEwMjAuMzg1NiBjIDAuMDEyNTY5LDMuMzA5MiA2LjAxMTcxOSw4Ljk3NjYgNi4wMTE3MTksOC45NzY2IDAsMCA1Ljk4ODI4NywtNS42OTA3IDUuOTg4MjgxLC05IGwgMCwtMC4wNDUgYyAtMC4wMjUxNSwtMy4zMDkxIC0yLjcyNDAxNCwtNS45NzQxIC02LjAzMzIwMzEsLTUuOTU1MSB6IG0gMC4wMDk3NywyIGMgMi4yMDYyMDYxLC0wLjAxMyA0LjAwNjY5MzEsMS43NjI2IDQuMDIzNDMzMSwzLjk2ODggbCAwLDAuMDMxIGMgLTVlLTYsMi4yMDYyIC0zLjk5MjE4OCw2IC0zLjk5MjE4OCw2IDAsMCAtMy45OTk0MjQsLTMuNzc4MiAtNC4wMDc4MTIsLTUuOTg0NCAtMC4wMDg0LC0yLjIwNjIgMS43NzAzMzQ1LC00LjAwMyAzLjk3NjU2MjUsLTQuMDE1NiB6IiAgICAgICBpZD0icGF0aDEyNTY4IiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzY3NjY2Njc2NzYyIgLz4gICAgPHBhdGggICAgICAgc3R5bGU9Im9wYWNpdHk6MTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lIiAgICAgICBkPSJNIDEwIDIgQyA2LjY4NjI5MiAyIDQgNC42ODYzIDQgOCBDIDQgMTEuMzEzNyAxMCAxNyAxMCAxNyBDIDEwIDE3IDE2IDExLjMxMzcgMTYgOCBDIDE2IDQuNjg2MyAxMy4zMTM3MDggMiAxMCAyIHogTSAxMCA0IEMgMTIuMDcxMDY4IDQgMTMuNzUgNS42Nzg5IDEzLjc1IDcuNzUgQyAxMy43NSA5LjIwNTMyNzggMTEuOTMxMTEgMTEuNjQ0MzkzIDEwLjgzMDA3OCAxMyBMIDkuMTY5OTIxOSAxMyBDIDguMDY4ODkwMyAxMS42NDQzOTMgNi4yNSA5LjIwNTMyNzggNi4yNSA3Ljc1IEMgNi4yNSA1LjY3ODkgNy45Mjg5MzIgNCAxMCA0IHogIiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDEwMzIuMzYyMikiICAgICAgIGlkPSJwYXRoMTczMDUiIC8+ICA8L2c+PC9zdmc+);
31 | }
32 |
33 | .mapbox-gl-draw_line {
34 | background-repeat: no-repeat;
35 | background-position: center;
36 | pointer-events: auto;
37 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJsaW5lLnN2ZyI+ICA8ZGVmcyAgICAgaWQ9ImRlZnMxOTE2OSIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIGlkPSJiYXNlIiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiICAgICBib3JkZXJvcGFjaXR5PSIxLjAiICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOnpvb209IjE2IiAgICAgaW5rc2NhcGU6Y3g9IjEyLjg5ODc3NSIgICAgIGlua3NjYXBlOmN5PSI5LjU4OTAxNTIiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBkPSJtIDEzLjUsMTAzNS44NjIyIGMgLTEuMzgwNzEyLDAgLTIuNSwxLjExOTMgLTIuNSwyLjUgMCwwLjMyMDggMC4wNDYxNCwwLjYyNDQgMC4xNTYyNSwwLjkwNjMgbCAtMy43NSwzLjc1IGMgLTAuMjgxODM2LC0wLjExMDIgLTAuNTg1NDIxLC0wLjE1NjMgLTAuOTA2MjUsLTAuMTU2MyAtMS4zODA3MTIsMCAtMi41LDEuMTE5MyAtMi41LDIuNSAwLDEuMzgwNyAxLjExOTI4OCwyLjUgMi41LDIuNSAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTAuMzIwOCAtMC4wNDYxNCwtMC42MjQ0IC0wLjE1NjI1LC0wLjkwNjIgbCAzLjc1LC0zLjc1IGMgMC4yODE4MzYsMC4xMTAxIDAuNTg1NDIxLDAuMTU2MiAwLjkwNjI1LDAuMTU2MiAxLjM4MDcxMiwwIDIuNSwtMS4xMTkzIDIuNSwtMi41IDAsLTEuMzgwNyAtMS4xMTkyODgsLTIuNSAtMi41LC0yLjUgeiIgICAgICAgaWQ9InJlY3Q2NDY3IiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPiAgPC9nPjwvc3ZnPg==);
38 | }
39 |
40 | .mapbox-gl-draw_polygon {
41 | background-repeat: no-repeat;
42 | background-position: center;
43 | pointer-events: auto;
44 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjIwIiAgIGhlaWdodD0iMjAiICAgdmlld0JveD0iMCAwIDIwIDIwIiAgIGlkPSJzdmcxOTE2NyIgICB2ZXJzaW9uPSIxLjEiICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45MStkZXZlbCtvc3htZW51IHIxMjkxMSIgICBzb2RpcG9kaTpkb2NuYW1lPSJzcXVhcmUuc3ZnIj4gIDxkZWZzICAgICBpZD0iZGVmczE5MTY5IiAvPiAgPHNvZGlwb2RpOm5hbWVkdmlldyAgICAgaWQ9ImJhc2UiICAgICBwYWdlY29sb3I9IiNmZmZmZmYiICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIgICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIiAgICAgaW5rc2NhcGU6em9vbT0iMTEuMzEzNzA4IiAgICAgaW5rc2NhcGU6Y3g9IjExLjY4MTYzNCIgICAgIGlua3NjYXBlOmN5PSI5LjI4NTcxNDMiICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiICAgICBzaG93Z3JpZD0idHJ1ZSIgICAgIHVuaXRzPSJweCIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4MCIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlua3NjYXBlOndpbmRvdy14PSIwIiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjIzIiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgICAgIGlua3NjYXBlOm9iamVjdC1ub2Rlcz0idHJ1ZSI+ICAgIDxpbmtzY2FwZTpncmlkICAgICAgIHR5cGU9Inh5Z3JpZCIgICAgICAgaWQ9ImdyaWQxOTcxNSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGExOTE3MiI+ICAgIDxyZGY6UkRGPiAgICAgIDxjYzpXb3JrICAgICAgICAgcmRmOmFib3V0PSIiPiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+ICAgICAgICA8ZGM6dHlwZSAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4gICAgICAgIDxkYzp0aXRsZSAvPiAgICAgIDwvY2M6V29yaz4gICAgPC9yZGY6UkRGPiAgPC9tZXRhZGF0YT4gIDxnICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIgICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiICAgICBpZD0ibGF5ZXIxIiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAzMi4zNjIyKSI+ICAgIDxwYXRoICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41O21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGQ9Im0gNSwxMDM5LjM2MjIgMCw2IDIsMiA2LDAgMiwtMiAwLC02IC0yLC0yIC02LDAgeiBtIDMsMCA0LDAgMSwxIDAsNCAtMSwxIC00LDAgLTEsLTEgMCwtNCB6IiAgICAgICBpZD0icmVjdDc3OTciICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjY2NjIiAvPiAgICA8Y2lyY2xlICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBpZD0icGF0aDQzNjQiICAgICAgIGN4PSI2IiAgICAgICBjeT0iMTA0Ni4zNjIyIiAgICAgICByPSIyIiAvPiAgICA8Y2lyY2xlICAgICAgIGlkPSJwYXRoNDM2OCIgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjYwMDAwMDAyO21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiICAgICAgIGN4PSIxNCIgICAgICAgY3k9IjEwNDYuMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBpZD0icGF0aDQzNzAiICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS42MDAwMDAwMjttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAgICAgICBjeD0iNiIgICAgICAgY3k9IjEwMzguMzYyMiIgICAgICAgcj0iMiIgLz4gICAgPGNpcmNsZSAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuNjAwMDAwMDI7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgICAgICAgaWQ9InBhdGg0MzcyIiAgICAgICBjeD0iMTQiICAgICAgIGN5PSIxMDM4LjM2MjIiICAgICAgIHI9IjIiIC8+ICA8L2c+PC9zdmc+);
45 | }
46 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/README.md:
--------------------------------------------------------------------------------
1 | # mapbox-gl-button-control
2 |
3 | add button or html element to Mapbox Control Bar
4 |
5 | Npm module created from https://codepen.io/roblabs/pen/zJjPzX
6 |
7 | See Example folder
8 |
9 | you will need to add your own mapbox access token for the demo in the index.js
10 |
11 |
12 | ```csharp
13 | cd Example
14 |
15 | npm install
16 |
17 | npm start
18 | ```
19 |
20 |
21 |
22 | 
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delebash/unreal_mapbox_bridge/63d2de18aef09b7ddba6c625675ed1cfb2ee6c5b/src/maptiler-gl-button-control/example.png
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/index.js:
--------------------------------------------------------------------------------
1 | /* Npm module created from https://codepen.io/roblabs/pen/zJjPzX */
2 | class MapTilerGLButtonControl {
3 | constructor({
4 | className = "",
5 | title = "",
6 | eventHandler = evtHndlr
7 | }) {
8 | this._className = className;
9 | this._title = title;
10 | this._eventHandler = eventHandler;
11 | }
12 |
13 | onAdd(map) {
14 | this._btn = document.createElement("button");
15 | this._btn.className = "maplibregl-ctrl-icon" + " " + this._className;
16 | this._btn.type = "button";
17 | this._btn.title = this._title;
18 | this._btn.onclick = this._eventHandler;
19 |
20 | this._container = document.createElement("div");
21 | this._container.className = "maplibregl-ctrl-group maplibregl-ctrl";
22 | this._container.appendChild(this._btn);
23 |
24 | return this._container;
25 | }
26 |
27 | onRemove() {
28 | this._container.parentNode.removeChild(this._container);
29 | this._map = undefined;
30 | }
31 | }
32 |
33 | export default MapTilerGLButtonControl
34 |
--------------------------------------------------------------------------------
/src/maptiler-gl-button-control/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@delebash/mapbox-gl-button-control",
3 | "version": "1.0.4",
4 | "description": "Easily add custom buttons to Mapbox Control Panel",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Daniel Elebash",
10 | "license": "ISC",
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/delebash/mapbox-gl-button-control.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/delebash/mapbox-gl-button-control/issues"
17 | },
18 | "homepage": "https://github.com/delebash/mapbox-gl-button-control#readme"
19 | }
20 |
--------------------------------------------------------------------------------
/src/pages/ErrorNotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 404
6 |
7 |
8 |
9 | Oops. Nothing here...
10 |
11 |
12 |
21 |
22 |
23 |
24 |
25 |
32 |
--------------------------------------------------------------------------------
/src/pages/IndexPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
17 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { route } from 'quasar/wrappers'
2 | import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router'
3 | import routes from './routes'
4 |
5 | /*
6 | * If not building with SSR mode, you can
7 | * directly export the Router instantiation;
8 | *
9 | * The function below can be async too; either use
10 | * async/await or return a Promise which resolves
11 | * with the Router instance.
12 | */
13 |
14 | export default route(function (/* { store, ssrContext } */) {
15 | const createHistory = process.env.SERVER
16 | ? createMemoryHistory
17 | : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
18 |
19 | const Router = createRouter({
20 | scrollBehavior: () => ({ left: 0, top: 0 }),
21 | routes,
22 |
23 | // Leave this as is and make changes in quasar.conf.js instead!
24 | // quasar.conf.js -> build -> vueRouterMode
25 | // quasar.conf.js -> build -> publicPath
26 | history: createHistory(process.env.VUE_ROUTER_BASE)
27 | })
28 |
29 | return Router
30 | })
31 |
--------------------------------------------------------------------------------
/src/router/routes.js:
--------------------------------------------------------------------------------
1 |
2 | const routes = [
3 | {
4 | path: '/',
5 | component: () => import('layouts/MainLayout.vue'),
6 | children: [
7 | { path: '', component: () => import('pages/IndexPage.vue') }
8 | ]
9 | },
10 |
11 | // Always leave this as last one,
12 | // but you can also remove it
13 | {
14 | path: '/:catchAll(.*)*',
15 | component: () => import('pages/ErrorNotFound.vue')
16 | }
17 | ]
18 |
19 | export default routes
20 |
--------------------------------------------------------------------------------
/src/utilities/combine-tiles-jimp.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import minBy from 'lodash/minBy';
4 | import maxBy from 'lodash/maxBy';
5 | import sortBy from 'lodash/sortBy';
6 |
7 | // import Jimp from 'jimp/browser/lib/jimp';
8 |
9 |
10 | export async function combineTilesJimp(tiles, tWidth, tHeight) {
11 | const offsetX = minBy(tiles, tile => tile.x).x
12 | const offsetY = minBy(tiles, tile => tile.y).y
13 |
14 | const makeRelative = (tile) => ({
15 | x: tile.x - offsetX,
16 | y: tile.y - offsetY,
17 | buffer: tile.buffer
18 | })
19 |
20 | const index = sortBy(tiles.map(makeRelative), ['y', 'x'])
21 | const cols = 1 + maxBy(index, tile => tile.x).x
22 | const rows = 1 + maxBy(index, tile => tile.y).y
23 | const w = tWidth * cols
24 | const h = tHeight * rows
25 |
26 | async function CompositeImg(image) {
27 | for (let data of index) {
28 | let buffer = Buffer.from(data.buffer)
29 | let y = data.y * tHeight
30 | let x = data.x * tWidth
31 | let newImage = await Jimp.read(buffer)
32 | image.composite(newImage, x, y)
33 | }
34 | return image
35 | }
36 |
37 | let image = await Jimp.read(Buffer.from(index[0].buffer))
38 | image.background(0xFFFFFFFF)
39 | image.resize(w, h);
40 | let compImage = await CompositeImg(image)
41 |
42 | let buffer = await compImage.getBufferAsync(Jimp.MIME_PNG);
43 |
44 | return buffer
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/utilities/emitter.js:
--------------------------------------------------------------------------------
1 | import mitt from 'mitt';
2 | export default mitt();
3 |
--------------------------------------------------------------------------------
/src/utilities/fs-helpers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Open a handle to an existing file on the local file system.
3 | *
4 | * @return {!Promise} Handle to the existing file.
5 | */
6 | function getFileHandle() {
7 | // For Chrome 86 and later...
8 | if ('showOpenFilePicker' in window) {
9 | return window.showOpenFilePicker().then((handles) => handles[0]);
10 | }
11 | }
12 |
13 | /**
14 | * Open a handle to a directory on the local file system.
15 | *
16 | * @return {!Promise} Handle to the existing file.
17 | */
18 | function getDirHandle() {
19 | // For Chrome 86 and later...
20 | if ('showDirectoryPicker' in window) {
21 | return window.showDirectoryPicker().then((handles) => handles);
22 | }
23 | }
24 |
25 | /**
26 | * Create a handle to a new (text) file on the local file system.
27 | *
28 | * @return {!Promise} Handle to the new file.
29 | */
30 | function getNewFileHandle() {
31 | // For Chrome 86 and later...
32 | if ('showSaveFilePicker' in window) {
33 | const opts = {
34 | types: [{
35 | description: 'Text file', accept: {'text/plain': ['.txt']},
36 | }],
37 | };
38 | return window.showSaveFilePicker(opts);
39 | }
40 | }
41 |
42 | /**
43 | * Reads the raw text from a file.
44 | *
45 | * @param {File} file
46 | * @return {!Promise} A promise that resolves to the parsed string.
47 | */
48 | function readFile(file) {
49 | // If the new .text() reader is available, use it.
50 | if (file.text) {
51 | return file.text();
52 | }
53 | }
54 |
55 | /**
56 | * Writes the contents to disk.
57 | *
58 | * @param {FileSystemFileHandle} fileHandle File handle to write to.
59 | * @param {string} contents Contents to write.
60 | */
61 | async function writeFile(fileHandle, contents) {
62 | // For Chrome 83 and later.
63 | // Create a FileSystemWritableFileStream to write to.
64 | const writable = await fileHandle.createWritable();
65 | // Write the contents of the file to the stream.
66 | await writable.write(contents);
67 | // Close the file and write the contents to disk.
68 | await writable.close();
69 | }
70 |
71 | /**
72 | * Verify the user has granted permission to read or write to the file, if
73 | * permission hasn't been granted, request permission.
74 | *
75 | * @param {FileSystemDirHandle} dirHandle Dir handle to check.
76 | * @param {boolean} withWrite True if write permission should be checked.
77 | * @return {boolean} True if permission granted.
78 |
79 | */
80 | async function verifyPermission(dirHandle, withWrite) {
81 | const opts = {};
82 | if (withWrite) {
83 | opts.writable = true;
84 | opts.mode = 'readwrite';
85 | }
86 | // Check if we already have permission, if so, return true.
87 | if (await dirHandle.queryPermission(opts) === 'granted') {
88 | return true;
89 | }
90 | // Request permission to the file, if the user grants permission, return true.
91 | if (await dirHandle.requestPermission(opts) === 'granted') {
92 | return true;
93 | }
94 | // The user did nt grant permission, return false.
95 | return false;
96 | }
97 |
98 | /**
99 | * Writes the contents to disk.
100 | *
101 | * @param {FileSystemDirHandle} dirHandle Dir handle to write to.
102 | * @param {string} fileName File name including extension.
103 | * @param {string, ArrayBuffer} contents Contents to write.
104 | */
105 | async function writeFileToDisk(dirHandle, fileName, contents) {
106 | let writeFileHandle = await dirHandle.getFileHandle(fileName, {create: true})
107 | let writable = await writeFileHandle.createWritable()
108 | await writable.write(contents)
109 | await writable.close();
110 | }
111 |
112 | /**
113 | * Check if file exists on disk.
114 | *
115 | * @param {FileSystemDirHandle} dirHandle Dir handle to write to.
116 | * @param {string} fileName File name including extension.
117 | * @return {boolean} True if file exists.
118 | */
119 | async function fileExists(dirHandle, fileName) {
120 | try {
121 | await dirHandle.getFileHandle(fileName)
122 | // console.log(fileName + ' file already exists -- using cached file')
123 | return true
124 | } catch (e) {
125 | if (e.name === "NotFoundError") {
126 | // console.log(fileName + ' File not found try to download')
127 | return false
128 | }
129 | if (e.name === "NotAllowedError") {
130 | console.log('Please select directory to verify permissions')
131 | return false
132 | }
133 | }
134 | }
135 |
136 | /**
137 | * Writes the contents to disk.
138 | *
139 | * @param {FileSystemDirHandle} dirHandle Dir handle to write to.
140 | * @param {string} fileName File name including extension.
141 | * @return {ArrayBuffer} arrBuffer of image information.
142 | */
143 |
144 | async function readFileFromDisk(dirHandle, fileName) {
145 | let fileHandle = await dirHandle.getFileHandle(fileName)
146 | const file = await fileHandle.getFile();
147 | const imageArrayBuffer = await file.arrayBuffer();
148 | return imageArrayBuffer
149 | }
150 |
151 | function checkFileApiSupport() {
152 | let bEnabled
153 | if ('showDirectoryPicker' in window) {
154 | bEnabled = true
155 | }else{
156 | bEnabled = false
157 | }
158 | // let bEnabled = true
159 | // try {
160 | // if(window.showDirectoryPicker())
161 | // const dirHandle = window.showDirectoryPicker()
162 | // } catch (e) {
163 | // if (e.message === 'window.showDirectoryPicker is not a function') {
164 | // bEnabled = false
165 | // }
166 | // }
167 | return bEnabled
168 | }
169 |
170 | export default {
171 | getDirHandle, verifyPermission, writeFileToDisk, fileExists, getFileHandle, readFileFromDisk, checkFileApiSupport
172 | }
173 |
--------------------------------------------------------------------------------
/src/utilities/idb-keyval-iife.js:
--------------------------------------------------------------------------------
1 | /* From https://github.com/jakearchibald/idb-keyval */
2 |
3 | /* Retreived 2020-04-10 */
4 | class Store {
5 | constructor(dbName = 'unreal-mapbox', storeName = 'keyval') {
6 | this.storeName = storeName;
7 | this._dbp = new Promise((resolve, reject) => {
8 | const openreq = indexedDB.open(dbName, 3);
9 | openreq.onerror = () => reject(openreq.error);
10 | openreq.onsuccess = () => resolve(openreq.result);
11 | // First time setup: create an empty object store
12 | openreq.onupgradeneeded = () => {
13 | try {
14 | openreq.result.deleteObjectStore(storeName);
15 | } catch (e) {
16 | //ignore
17 | }
18 | openreq.result.createObjectStore(storeName);
19 | };
20 | });
21 | }
22 |
23 | _withIDBStore(type, callback) {
24 | return this._dbp.then(db => new Promise((resolve, reject) => {
25 | const transaction = db.transaction(this.storeName, type);
26 | transaction.oncomplete = () => resolve();
27 | transaction.onabort = transaction.onerror = () => reject(transaction.error);
28 | callback(transaction.objectStore(this.storeName));
29 | }));
30 | }
31 | }
32 |
33 | let store;
34 |
35 | function getDefaultStore() {
36 | if (!store)
37 | store = new Store();
38 | return store;
39 | }
40 |
41 | function get(key, store = getDefaultStore()) {
42 | let req;
43 | return store._withIDBStore('readonly', store => {
44 | req = store.get(key);
45 | }).then(() => req.result);
46 | }
47 |
48 | function set(key, value, store = getDefaultStore()) {
49 | return store._withIDBStore('readwrite', store => {
50 | store.put(value, key);
51 | });
52 | }
53 |
54 | function del(key, store = getDefaultStore()) {
55 | return store._withIDBStore('readwrite', store => {
56 | store.delete(key);
57 | });
58 | }
59 |
60 | function clear(store = getDefaultStore()) {
61 | return store._withIDBStore('readwrite', store => {
62 | store.clear();
63 | });
64 | }
65 |
66 | function keys(store = getDefaultStore()) {
67 | const keys = [];
68 | return store._withIDBStore('readonly', store => {
69 | // This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
70 | // And openKeyCursor isn't supported by Safari.
71 | (store.openKeyCursor || store.openCursor).call(store).onsuccess = function () {
72 | if (!this.result)
73 | return;
74 | keys.push(this.result.key);
75 | this.result.continue();
76 | };
77 | }).then(() => keys);
78 | }
79 |
80 | export default {
81 | keys,
82 | clear,
83 | del,
84 | set,
85 | get
86 | }
87 |
--------------------------------------------------------------------------------
/src/utilities/map-utils.js:
--------------------------------------------------------------------------------
1 | import mapboxgl from "mapbox-gl";
2 | import tilebelt from '@mapbox/tilebelt'
3 | import * as turf from '@turf/turf'
4 | import {Image} from "image-js";
5 | import idbKeyval from "../utilities/idb-keyval-iife";
6 |
7 | function getTileInfo(lng, lat, multiple, x, y, z, bbox) {
8 | let tileInfo = {}
9 | let xyzpoint
10 |
11 |
12 | if (multiple === false) {
13 | xyzpoint = tilebelt.pointToTile(lng, lat, z)
14 | x = xyzpoint[0]
15 | y = xyzpoint[1]
16 | }
17 |
18 | let widthInMeters = 40075016.686 * Math.abs(Math.cos(lat)) / Math.pow(2, z);
19 | let metersPerPixel = widthInMeters / 512;
20 |
21 | tileInfo.z = z
22 | tileInfo.x = x
23 | tileInfo.y = y
24 | tileInfo.pointLng = lng
25 | tileInfo.pointLat = lat
26 | tileInfo.tileWidthInMeters = widthInMeters
27 | tileInfo.metersPerPixel = metersPerPixel
28 | tileInfo.mapboxTileName = tileInfo.z + "-" + tileInfo.x + "-" + tileInfo.y
29 | tileInfo.tile = [tileInfo.x, tileInfo.y, tileInfo.z] // x,y,z
30 | if (multiple === false) {
31 | tileInfo.bbox = tilebelt.tileToBBOX(tileInfo.tile);
32 | } else {
33 | tileInfo.bbox = bbox;
34 | }
35 | //tileInfo.bbox = tilebelt.tileToBBOX(tileInfo.tile);
36 | tileInfo.polygon_bb = getTileGeoJsonBB(tileInfo.bbox)
37 | tileInfo.area_bb = getAreaBB(tileInfo.bbox)
38 |
39 | const llb = new mapboxgl.LngLatBounds(tileInfo.bbox);
40 |
41 | //Corners of bbox
42 | tileInfo.bboxCT = llb.getCenter();
43 | tileInfo.bboxSW = llb.getSouthWest()
44 | tileInfo.bboxNE = llb.getNorthEast()
45 | tileInfo.bboxNW = llb.getNorthWest()
46 | tileInfo.bboxSE = llb.getSouthEast()
47 |
48 | //Edge of bbox
49 | tileInfo.bboxW = llb.getWest().toFixed(5)
50 | tileInfo.bboxS = llb.getSouth().toFixed(5)
51 | tileInfo.bboxE = llb.getEast().toFixed(5)
52 | tileInfo.bboxN = llb.getNorth().toFixed(5)
53 |
54 | tileInfo.topLeft = tileInfo.bboxNW
55 | tileInfo.bottomLeft = tileInfo.bboxSW
56 | tileInfo.topRight = tileInfo.bboxNE
57 | tileInfo.bottomRight = tileInfo.bboxSE
58 | tileInfo.center = tileInfo.bboxCT
59 |
60 |
61 | const topLeft = turf.point([tileInfo.bboxNE.lng, tileInfo.bboxNE.lat]);
62 | const topRight = turf.point([tileInfo.bboxSW.lng, tileInfo.bboxNE.lat]);
63 | const bottomLeft = turf.point([tileInfo.bboxNE.lng, tileInfo.bboxSW.lat]);
64 | const bottomRight = turf.point([tileInfo.bboxSW.lng, tileInfo.bboxSW.lat]);
65 | const middleLeft = turf.midpoint(topLeft, bottomLeft);
66 | const middleRight = turf.midpoint(topRight, bottomRight);
67 | tileInfo.distance = turf.distance(middleLeft, middleRight, 'kilometers').toFixed(2);
68 |
69 | tileInfo.maxPngValue = 65535
70 | tileInfo.rgbFileName = 'terrain-rgb' + '-' + tileInfo.mapboxTileName + '.png'
71 | tileInfo.mapFileName = 'map' + '-' + tileInfo.mapboxTileName + '.png'
72 | tileInfo.satFileName = 'sat' + '-' + tileInfo.mapboxTileName + '.png'
73 | tileInfo.thirtyTwoFileName = 'thirtytwo' + '-' + tileInfo.mapboxTileName + '.png'
74 | tileInfo.tileInfoFileName = 'tile-info' + '-' + tileInfo.mapboxTileName + '.json'
75 | tileInfo.geoJsonFileName = 'geojson' + '-' + tileInfo.mapboxTileName + '.json'
76 |
77 | return tileInfo
78 | }
79 |
80 | // function traverseArray(arr) {
81 | // let i = 0
82 | // let lng
83 | // let lat
84 | //
85 | // arr.forEach((element, index) => {
86 | // if (Array.isArray(element)) {
87 | // traverseArray(element);
88 | // } else {
89 | // if (i === 0) {
90 | // lng = element
91 | // }
92 | // if (i === 1) {
93 | // lat = element
94 | // let convUtm = converLatLngTotUtm(lat, lng)
95 | // arr[0] = convUtm.northing
96 | // arr[1] = convUtm.easting
97 | // }
98 | // i = i + 1
99 | // if (i === 2) {
100 | // i = 0
101 | // }
102 | // }
103 | // });
104 | // }
105 |
106 | function getAreaBB(bbox) {
107 |
108 | let poly = turf.bboxPolygon(bbox);
109 | let area = turf.area(poly);
110 | return area
111 | }
112 |
113 | function getTileGeoJsonBB(bbox) {
114 | let poly = turf.bboxPolygon(bbox);
115 | let geoJson = {
116 | 'type': 'Feature', 'geometry': {
117 | 'type': poly.geometry.type, 'coordinates': poly.geometry.coordinates
118 | }
119 | };
120 | return geoJson;
121 | }
122 |
123 | function getFeaturesFromBB(map, tile_info, combine) {
124 | tile_info.swPt = map.project(tile_info.bboxSW)
125 | tile_info.nePt = map.project(tile_info.bboxNE)
126 | tile_info.nwPt = map.project(tile_info.bboxNW)
127 | tile_info.sePt = map.project(tile_info.bboxSE)
128 | let features = map.queryRenderedFeatures([tile_info.swPt, tile_info.nePt])
129 |
130 | if (combine === true) {
131 | features = getUniqueFeatures(features)
132 | }
133 | return features
134 |
135 | }
136 |
137 | // Because features come from tiled vector data,
138 | // feature geometries may be split
139 | // or duplicated across tile boundaries.
140 | // As a result, features may appear
141 | // multiple times in query results.
142 | function getUniqueFeatures(features) {
143 | const uniqueIds = new Set();
144 | const uniqueFeatures = [];
145 | for (const feature of features) {
146 | const name = feature.properties["name"];
147 | const type = feature.geometry["type"];
148 | let id = name + '-' + type
149 | if (!uniqueIds.has(id)) {
150 | uniqueIds.add(id);
151 | uniqueFeatures.push(feature);
152 | }
153 | }
154 | return uniqueFeatures;
155 | }
156 |
157 | /**
158 | * Load image-js image from array
159 | *
160 | * @param {ArrayBuffer} imageArray ArrayBuffer representing image values
161 | * @return {image-js} Image-js image.
162 | */
163 | async function loadImageFromArray(imageArray) {
164 | try {
165 | let image = await Image.load(imageArray)
166 | return image
167 | } catch (e) {
168 | console.log(e)
169 | }
170 | }
171 |
172 | /**
173 | * Calculate height in meters from RGB height encoded pixels using Mapbox formula.
174 | *
175 | * @param {int} r Red pixel channel
176 | * @param {int} g Green pixel channel
177 | * @param {int} b Blue pixel channel
178 | * @return {height} New height value.
179 | */
180 | function getHeightFromRgb(r, g, b) {
181 | return -10000 + ((r * 256 * 256 + g * 256 + b) * 0.1);
182 | }
183 |
184 | /**
185 | * Decode rgb height from image.
186 | *
187 | * @param {image-js} image Image created from image-js
188 | * @return {int[]} Decoded height array.
189 | */
190 | function getHeightArray(image) {
191 | let decodedHeightArray = []
192 | let pixelsArray = image.getPixelsArray()
193 | for (const pixel of pixelsArray) {
194 | let r = pixel[0]
195 | let g = pixel[1]
196 | let b = pixel[2]
197 | let height = getHeightFromRgb(r, g, b)
198 | height = parseFloat(height)
199 | decodedHeightArray.push(height)
200 | }
201 |
202 | return decodedHeightArray
203 | }
204 |
205 | /**
206 | * Calculate Medium value of array
207 | *
208 | * @param {int[]} array of integers.
209 | * @return {int} integer Median value.
210 | */
211 | function getMedianArray(array) {
212 | const arr = array.filter(val => !!val);
213 | const sum = arr.reduce((sum, val) => (sum += val));
214 | const len = arr.length;
215 |
216 | const arrSort = arr.sort();
217 | const mid = Math.ceil(len / 2);
218 |
219 | const median = len % 2 == 0 ? (arrSort[mid] + arrSort[mid - 1]) / 2 : arrSort[mid - 1];
220 |
221 | return median
222 | }
223 |
224 | /**
225 | * Download RGB terrain png from Mapbox api
226 | *
227 | * @param {string} mapbox_rgb_image_url Request url to Mapbox api.
228 | * @return {ArrayBuffer} arrBuffer of image information.
229 | */
230 | async function downloadTerrainRgb(mapbox_rgb_image_url) {
231 | //Fetch png tile from mapbox
232 | const response = await fetch(mapbox_rgb_image_url);
233 | let arrBuffer = await response.arrayBuffer()
234 |
235 | return arrBuffer
236 | }
237 |
238 | async function unrealRemoteControl(data, url) {
239 | let response, dataJson = {}, error = ''
240 |
241 | const requestOptions = {
242 | method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)
243 | };
244 |
245 | try {
246 | response = await fetch(url, requestOptions);
247 | } catch (e) {
248 | error = e
249 | }
250 |
251 | dataJson.response = response
252 | dataJson.error = error
253 |
254 | return dataJson
255 |
256 | }
257 |
258 | /**
259 | * Check if RGB exists else initiate download
260 | *
261 | * @param {FileSystemDirHandle} dirHandle Dir handle to write to.
262 | * @param {object} tile_info Tile information for file name.
263 | * @param {string} mapbox_rgb_image_url Request url to Mapbox api.
264 | * @return {image-js} Image-js image.
265 | */
266 | async function getMapboxTerrainRgb(mapbox_rgb_image_url) {
267 | let rgbImageArrayBuffer
268 | let image
269 |
270 | rgbImageArrayBuffer = await downloadTerrainRgb(mapbox_rgb_image_url)
271 | image = await loadImageFromArray(rgbImageArrayBuffer)
272 | idbKeyval.set('rgbImageArrayBuffer', rgbImageArrayBuffer)
273 | return image
274 | }
275 |
276 | /**
277 | * Convert image to specified bit and color
278 | *
279 | * @param {int} width Image width.
280 | * @param {int} height Image width.
281 | * @param {int[]} imageArray Uint16Array representing image values
282 | * @param {int} bitDepth image-js bit depth example 8,16,32
283 | * @param {string} colorModel image-js color madel string.
284 | * @return {image-js} Image-js image.
285 | */
286 | function convertImage(width, height, imageArray, bitDepth, colorModel) {
287 | let newImage = new Image(width, height, imageArray, {kind: colorModel, bitDepth: bitDepth})
288 | return newImage
289 | }
290 |
291 | /**
292 | * Calculate Medium value of array
293 | *
294 | * @param {image-js} image Image created from image-js
295 | * @param {int} bitDepth image-js bit depth example 8,16,32
296 | * @param {string} colorModel image-js color madel string.
297 | * @return {object} image_info Obect containing image and stats
298 | */
299 | function createHeightMapImage(image, bitDepth, colorModel) {
300 | let image_info = {}
301 | let decodedHeightArray = getHeightArray(image)
302 | idbKeyval.set('decodedHeightArray', decodedHeightArray)
303 | let out_image = convertImage(image.width, image.height, decodedHeightArray, bitDepth, colorModel)
304 |
305 |
306 | image_info.minElevation = out_image.min[0];
307 | image_info.maxElevation = out_image.max[0];
308 | image_info.image = out_image
309 | image_info.decodedHeightArray = decodedHeightArray
310 |
311 | return image_info
312 | }
313 |
314 | export default {
315 | getTileInfo,
316 | getFeaturesFromBB,
317 | getMapboxTerrainRgb,
318 | createHeightMapImage,
319 | loadImageFromArray,
320 | unrealRemoteControl,
321 | downloadTerrainRgb,
322 | convertImage,
323 | getTileGeoJsonBB
324 | }
325 |
--------------------------------------------------------------------------------