@opengis/gis 0.1.66 → 0.1.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/module/gis/table/site.gis.registers.table.json +6 -0
- package/module/gis/table/site.gis.services.table.json +9 -16
- package/package.json +6 -6
- package/server/plugins/mapnik/funcs/map.proto +241 -0
- package/server/plugins/mapnik/funcs/mapnik.js +73 -72
- package/server/routes/map/controllers/rtile.js +1 -0
- package/server/routes/map/index.mjs +6 -0
- package/server/routes/map/vtile1.js +98 -0
- package/server/plugins/mapnik/index.mjs +0 -12
|
@@ -7,20 +7,6 @@
|
|
|
7
7
|
"title": "name",
|
|
8
8
|
"search": "name,description,source_path"
|
|
9
9
|
},
|
|
10
|
-
"sql": [
|
|
11
|
-
{
|
|
12
|
-
"sql": "select source, date_updated, size, region from gis.metadata where layer_id=t.service_id limit 1",
|
|
13
|
-
"name": "metadata_sql"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"sql": "select json_agg(q) as metadata_all from (select scale, katottg,srid, region, name, purpose, source,keywords,update_frequency,year,date_created,size,access_constraints,license from gis.metadata where layer_id=t.service_id limit 1)q ",
|
|
17
|
-
"name": "metadata_list_sql"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"name": "is_export_sql",
|
|
21
|
-
"sql": "select jsonb_path_exists(attributes, '$[*] ? (@.is_export == true)') as is_export"
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
10
|
"title": "Сервіси",
|
|
25
11
|
"form": "gis.services.form",
|
|
26
12
|
"sqlColumns": "*",
|
|
@@ -85,10 +71,17 @@
|
|
|
85
71
|
}
|
|
86
72
|
],
|
|
87
73
|
"filterList": [
|
|
74
|
+
{
|
|
75
|
+
"label": "Назва, Опис",
|
|
76
|
+
"id": "search",
|
|
77
|
+
"type": "Text",
|
|
78
|
+
"columns": "name,description",
|
|
79
|
+
"inline": true
|
|
80
|
+
},
|
|
88
81
|
{
|
|
89
82
|
"label": "Ключові слова",
|
|
90
83
|
"id": "keywords",
|
|
91
|
-
"type": "
|
|
84
|
+
"type": "Check",
|
|
92
85
|
"inline": true
|
|
93
86
|
},
|
|
94
87
|
{
|
|
@@ -108,7 +101,7 @@
|
|
|
108
101
|
{
|
|
109
102
|
"label": "Утримувач",
|
|
110
103
|
"id": "holder",
|
|
111
|
-
"type": "
|
|
104
|
+
"type": "Check"
|
|
112
105
|
}
|
|
113
106
|
]
|
|
114
107
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/gis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.68",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Softpro",
|
|
6
|
-
"main": "dist/
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist/*",
|
|
9
9
|
"module/*",
|
|
@@ -28,20 +28,20 @@
|
|
|
28
28
|
"docs:preview": "npm run --prefix ./docs docs:preview",
|
|
29
29
|
"prepublishOnly": "npm run build"
|
|
30
30
|
},
|
|
31
|
-
"dependencies": {
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@mapbox/sphericalmercator": "1.2.0",
|
|
33
|
+
"carto": "0.16.3"
|
|
34
|
+
},
|
|
32
35
|
"peerDependencies": {
|
|
33
36
|
"@opengis/fastify-table": "^1.4.24",
|
|
34
37
|
"@opengis/filter": "^0.1.7",
|
|
35
38
|
"@opengis/core": "^0.0.18"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
38
|
-
"@mapbox/sphericalmercator": "1.2.0",
|
|
39
41
|
"lucide-vue-next": "^0.514.0",
|
|
40
|
-
"carto": "0.16.3",
|
|
41
42
|
"vue": "^3.5.13",
|
|
42
43
|
"vue-router": "4.5.1",
|
|
43
44
|
"vuedraggable": "^4.1.0",
|
|
44
|
-
"yaml": "^2.8.0",
|
|
45
45
|
"@opengis/core": "^0.0.18",
|
|
46
46
|
"@opengis/filter": "^0.1.7",
|
|
47
47
|
"@opengis/fastify-table": "^1.4.77",
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
message render_in {
|
|
5
|
+
string path = 1;
|
|
6
|
+
string name = 2;
|
|
7
|
+
repeated double bbox = 3 [packed=true];
|
|
8
|
+
string tile = 4;
|
|
9
|
+
string xml = 5;
|
|
10
|
+
int32 width = 6;
|
|
11
|
+
int32 height = 7;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
message render_out {
|
|
16
|
+
string err = 1;
|
|
17
|
+
string base64 = 2;
|
|
18
|
+
string tile = 3;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
message xml_in {
|
|
22
|
+
string path = 1;
|
|
23
|
+
string name = 2;
|
|
24
|
+
string xml = 3;
|
|
25
|
+
bool reload = 4;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
message xml_out {
|
|
29
|
+
string err = 1;
|
|
30
|
+
bool is_ok = 2;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
message cmd_in {
|
|
34
|
+
string cmd = 1;
|
|
35
|
+
string svg = 2;
|
|
36
|
+
string filename = 3;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
message cmd_out {
|
|
40
|
+
string err = 1;
|
|
41
|
+
string base64 = 2;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
message gdal_in {
|
|
45
|
+
string name = 1;
|
|
46
|
+
string path = 2;
|
|
47
|
+
string out = 3;
|
|
48
|
+
string params = 4;
|
|
49
|
+
}
|
|
50
|
+
message gdal_out {
|
|
51
|
+
string result = 1;
|
|
52
|
+
string err = 2;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
message clear_tiles_in {
|
|
56
|
+
string path = 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
message clear_tiles_out {
|
|
60
|
+
oneof clear_message {
|
|
61
|
+
bool ok = 1;
|
|
62
|
+
string err = 2;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
message empty {}
|
|
67
|
+
|
|
68
|
+
message statusRenderInfo {
|
|
69
|
+
string name = 1;
|
|
70
|
+
bool isActive = 2;
|
|
71
|
+
float workTime = 3;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
message statusInfo {
|
|
75
|
+
repeated statusRenderInfo info = 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
message printMapOut {
|
|
79
|
+
string map = 1;
|
|
80
|
+
string err = 2;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
message xyz {
|
|
84
|
+
float x = 1;
|
|
85
|
+
float y = 2;
|
|
86
|
+
float z = 3;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
message printMapIn {
|
|
90
|
+
string baseurl = 1;
|
|
91
|
+
string baseImg = 2;
|
|
92
|
+
repeated string xml = 3;
|
|
93
|
+
string overlayXml = 4;
|
|
94
|
+
string overlay = 5;
|
|
95
|
+
int32 width = 6;
|
|
96
|
+
int32 height = 7;
|
|
97
|
+
repeated double bbox = 8;
|
|
98
|
+
xyz pos = 9;
|
|
99
|
+
string geojsonSettings = 10;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
message log_in {
|
|
103
|
+
uint32 rows = 1;
|
|
104
|
+
string level = 2;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
message log_out {
|
|
108
|
+
repeated string logs = 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
message sqlToShpIn {
|
|
112
|
+
string db = 1;
|
|
113
|
+
string host = 2;
|
|
114
|
+
string port = 3;
|
|
115
|
+
string sql = 4;
|
|
116
|
+
string savePath = 5;
|
|
117
|
+
string shpName = 6;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
message shapeOut {
|
|
121
|
+
string zipPath = 1;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
message fileIn {
|
|
125
|
+
bytes fileBytes = 1;
|
|
126
|
+
string relativeFilepath = 2;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
message deleteFileIn {
|
|
130
|
+
string dir = 1;
|
|
131
|
+
repeated string objectList = 2;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
message fileManagerOut {
|
|
135
|
+
bool status = 1;
|
|
136
|
+
string operation = 2;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
message checkFilesDir {
|
|
140
|
+
string dir = 1;
|
|
141
|
+
repeated string filesSearch = 2;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
enum status {
|
|
145
|
+
LOADING = 0;
|
|
146
|
+
OK = 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
message filesStatus {
|
|
150
|
+
status fileLoadingStatus = 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
message fileListIn {
|
|
154
|
+
string dir = 1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
message fileInfo {
|
|
158
|
+
repeated fileInfoL fileInfoList = 1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
message fileInfoL {
|
|
162
|
+
oneof fileInfo {
|
|
163
|
+
fileInfoObj file = 1;
|
|
164
|
+
dirInfoObj dir = 2;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
message fileInfoObj {
|
|
169
|
+
string type = 1;
|
|
170
|
+
string birthtime = 2;
|
|
171
|
+
string name = 3;
|
|
172
|
+
uint64 size = 4;
|
|
173
|
+
string ext = 5;
|
|
174
|
+
string server = 6;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
message dirInfoObj {
|
|
178
|
+
string type = 1;
|
|
179
|
+
string birthtime = 2;
|
|
180
|
+
string name = 3;
|
|
181
|
+
uint64 size = 4;
|
|
182
|
+
uint64 count = 5;
|
|
183
|
+
string server = 6;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
message deleteOut {
|
|
187
|
+
repeated deleteObjSuccess success = 1;
|
|
188
|
+
repeated deleteObjError error = 2;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
message deleteObjSuccess {
|
|
193
|
+
string object = 1;
|
|
194
|
+
string type = 2;
|
|
195
|
+
string status = 3;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
message deleteObjError {
|
|
199
|
+
string object = 1;
|
|
200
|
+
string fullPath = 2;
|
|
201
|
+
string result = 3;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
message readDirIn {
|
|
205
|
+
string dir = 1;
|
|
206
|
+
repeated string filter = 2;
|
|
207
|
+
string fullPath = 3;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
message readDirOut {
|
|
211
|
+
repeated string res = 1;
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
message downloadFileIn {
|
|
216
|
+
string filePath = 1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
message downloadFileOut {
|
|
220
|
+
bytes chunk_data = 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
service Map {
|
|
225
|
+
rpc Render(render_in) returns (render_out) {}
|
|
226
|
+
rpc RenderXML(render_in) returns (render_out) {}
|
|
227
|
+
rpc LoadXML(xml_in) returns (xml_out) {}
|
|
228
|
+
rpc MarkerIcon(cmd_in) returns (cmd_out) {}
|
|
229
|
+
rpc Gdal(gdal_in) returns (gdal_out) {}
|
|
230
|
+
rpc ClearTiles(clear_tiles_in) returns (clear_tiles_out) {}
|
|
231
|
+
rpc RenderStatus(empty) returns (statusInfo) {}
|
|
232
|
+
rpc PrintMap(printMapIn) returns (printMapOut) {}
|
|
233
|
+
rpc Log(log_in) returns (log_out) {}
|
|
234
|
+
rpc SqlToShp(sqlToShpIn) returns (shapeOut) {}
|
|
235
|
+
rpc uploadFile(fileIn) returns (fileManagerOut) {}
|
|
236
|
+
rpc deleteFiles(deleteFileIn) returns (deleteOut) {}
|
|
237
|
+
rpc checkFiles(checkFilesDir) returns (filesStatus) {}
|
|
238
|
+
rpc fileList(fileListIn) returns (fileInfo) {}
|
|
239
|
+
rpc readDir(readDirIn) returns (readDirOut) {}
|
|
240
|
+
rpc downloadFile(downloadFileIn) returns (stream downloadFileOut) {}
|
|
241
|
+
}
|
|
@@ -9,89 +9,90 @@ import { config, logger } from '@opengis/fastify-table/utils.js';
|
|
|
9
9
|
config.ready = config.ready || {};
|
|
10
10
|
|
|
11
11
|
const { mapServerAddress } = config || {};
|
|
12
|
-
|
|
12
|
+
const funcs1 =[]
|
|
13
13
|
if (!mapServerAddress) {
|
|
14
|
-
|
|
15
|
-
}
|
|
14
|
+
console.log("\x1b[34m%s\x1b[0m",'mapServerAddress not set in config');
|
|
15
|
+
} else {
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
protoLoader.loadSync(path.join(process.cwd(), '/server/plugins/mapnik/utils/map.proto'), {
|
|
19
|
-
keepCase: true,
|
|
20
|
-
longs: String,
|
|
21
|
-
enums: String,
|
|
22
|
-
defaults: true,
|
|
23
|
-
oneofs: true,
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
17
|
+
const PROTO_PATH = path.join(__dirname, 'map.proto')
|
|
26
18
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
const proto = grpc.loadPackageDefinition(
|
|
20
|
+
protoLoader.loadSync(PROTO_PATH, {
|
|
21
|
+
keepCase: true,
|
|
22
|
+
longs: String,
|
|
23
|
+
enums: String,
|
|
24
|
+
defaults: true,
|
|
25
|
+
oneofs: true,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
31
28
|
|
|
32
|
-
mapClient
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
const mapClient = mapServerAddress ? new proto.Map(
|
|
30
|
+
mapServerAddress,
|
|
31
|
+
grpc.credentials.createInsecure(),
|
|
32
|
+
) : null;
|
|
33
|
+
|
|
34
|
+
mapClient.waitForReady(Date.now() + 5000, (err) => {
|
|
35
|
+
if (err) {
|
|
36
|
+
config.ready.mapnik = false;
|
|
37
|
+
console.error('Mapnik client connection timeout or failure:', err);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
config.ready.mapnik = true;
|
|
41
|
+
console.log('Mapnik client connected successfully.');
|
|
42
|
+
// You can now make RPC calls safely
|
|
43
|
+
}
|
|
44
|
+
});
|
|
43
45
|
|
|
44
|
-
const fsFuncsList = ['uploadFile', 'deleteFiles', 'downloadFile', 'checkFiles', 'fileList', 'readDir'];
|
|
46
|
+
const fsFuncsList = ['uploadFile', 'deleteFiles', 'downloadFile', 'checkFiles', 'fileList', 'readDir'];
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
].
|
|
51
|
-
// eslint-disable-next-line no-param-reassign
|
|
52
|
-
p[el] = mapServerAddress ? async (data) => new Promise((res, rej) => {
|
|
53
|
-
const capitalized = fsFuncsList.includes(el) ? el : el.charAt(0).toUpperCase() + el.slice(1);
|
|
48
|
+
[
|
|
49
|
+
'render', 'renderXML', 'loadXML', 'markerIcon', 'gdal',
|
|
50
|
+
'printMap', 'log', 'sqlToShp', 'uploadFile', 'deleteFiles',
|
|
51
|
+
'downloadFile', 'checkFiles', 'fileList', 'readDir', 'renderStatus',
|
|
52
|
+
].forEach(el => {
|
|
54
53
|
// eslint-disable-next-line no-param-reassign
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
funcs1[el] = mapServerAddress ? async (data) => new Promise((res, rej) => {
|
|
55
|
+
const capitalized = fsFuncsList.includes(el) ? el : el.charAt(0).toUpperCase() + el.slice(1);
|
|
56
|
+
// eslint-disable-next-line no-param-reassign
|
|
57
|
+
if (data) {
|
|
58
|
+
if (data?.path && data.path?.[0] !== '"') {
|
|
59
|
+
// eslint-disable-next-line no-param-reassign
|
|
60
|
+
data.path = `"${data.path}"`;
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
|
-
}
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
if (el === 'downloadFile') {
|
|
65
|
+
const downloadBuffer = [];
|
|
66
|
+
const download = mapClient[capitalized].call(mapClient, data, (err, data1) => {
|
|
67
|
+
if (err || data1?.result?.startsWith?.('Usage:')) {
|
|
68
|
+
logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
|
|
69
|
+
if (!config.ready.mapnik) {
|
|
70
|
+
return rej(new Error('no grpc mapnik connection'));
|
|
71
|
+
}
|
|
72
|
+
return rej(err || data1?.result);
|
|
69
73
|
}
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return rej(
|
|
74
|
+
res(data1);
|
|
75
|
+
});
|
|
76
|
+
download.on('data', (resp) => {
|
|
77
|
+
downloadBuffer.push(...resp.chunk_data);
|
|
78
|
+
});
|
|
79
|
+
download.on('end', () => res({ data: Buffer.from(downloadBuffer) }));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
mapClient[capitalized].call(mapClient, data, (err, data1) => {
|
|
83
|
+
if (err || data1?.result?.startsWith?.('Usage:')) {
|
|
84
|
+
logger.file('grpc/mapnik', { error: err.toString(), stack: err.stack, ready: config.ready.mapnik });
|
|
85
|
+
if (!config.ready.mapnik) {
|
|
86
|
+
return rej(new Error('no grpc mapnik connection'));
|
|
87
|
+
}
|
|
88
|
+
return rej(err || data1?.result);
|
|
85
89
|
}
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return p;
|
|
93
|
-
}, {});
|
|
94
|
-
|
|
90
|
+
res(data1);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}) : null;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
95
96
|
|
|
96
97
|
const getMapnik = () => ({
|
|
97
98
|
...funcs1,
|
|
@@ -33,6 +33,7 @@ const autoGenerate = {};
|
|
|
33
33
|
export default async function rtile({
|
|
34
34
|
pg = pgClients.client, params = {}, query = {}, user = {},
|
|
35
35
|
}, reply) {
|
|
36
|
+
if(!render) return reply.status(400).send('mapnik server address needed');
|
|
36
37
|
const { id, z, y } = params;
|
|
37
38
|
const { debug, nocache } = query;
|
|
38
39
|
const db = pg.options?.database;
|
|
@@ -6,6 +6,7 @@ import mapCatalog from './controllers/mapCatalog.js';
|
|
|
6
6
|
import mapCatalogAttribute from './controllers/mapCatalogAttribute.js';
|
|
7
7
|
import rtile from './controllers/rtile.js';
|
|
8
8
|
import vtile from './controllers/vtile.js';
|
|
9
|
+
import vtile1 from './vtile1.js';
|
|
9
10
|
|
|
10
11
|
import mapFormat from './controllers/mapFormat.js';
|
|
11
12
|
import maps from './controllers/maps.js';
|
|
@@ -49,6 +50,11 @@ export default async function route(app) {
|
|
|
49
50
|
app.get('/layer-rtile/:id/:z/:y/:x', { config: { policy }, schema: {} }, rtile);
|
|
50
51
|
app.get('/layer-vtile/:id/:z/:y/:x', { config: { policy }, schema: schemaInfo }, vtile);
|
|
51
52
|
|
|
53
|
+
if (!app.hasRoute({ method: 'GET', url: '/api/vtile/:layer/:lang/:z/:y/:x', })) {
|
|
54
|
+
console.log("\x1b[34m%s\x1b[0m",'add vtile from gis');
|
|
55
|
+
app.get('/vtile/:layer/:lang/:z/:y/:x', { config: { policy }, schema: schemaInfo }, vtile1);
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
app.get('/marker-icon/*', { config: { policy }, schema: {} }, markerIconApi);
|
|
53
59
|
app.get('/map-format', { config: { policy }, schema: {} }, mapFormat);
|
|
54
60
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const headers = {
|
|
2
|
+
'Content-Type': 'application/x-protobuf',
|
|
3
|
+
'Cache-Control': 'no-cache',
|
|
4
|
+
};
|
|
5
|
+
import Sphericalmercator from '@mapbox/sphericalmercator';
|
|
6
|
+
const mercator = new Sphericalmercator({ size: 256 });
|
|
7
|
+
import { getTemplate, getMeta, getFilterSQL } from '@opengis/fastify-table/utils.js';
|
|
8
|
+
|
|
9
|
+
export default async function vtile({ params = {}, query, pg }, reply) {
|
|
10
|
+
const { y, z, layer } = params;
|
|
11
|
+
const x = params.x.split('.')[0] - 0;
|
|
12
|
+
|
|
13
|
+
// layer
|
|
14
|
+
const data = await getTemplate('layer', layer);
|
|
15
|
+
if (!data) return { status: 404, message: 'not found' }
|
|
16
|
+
|
|
17
|
+
// bbox
|
|
18
|
+
const bbox = mercator.bbox(+y, +x, +z, false/* , '900913' */);
|
|
19
|
+
const bbox2d = `'BOX(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d`;
|
|
20
|
+
|
|
21
|
+
// columns
|
|
22
|
+
const geom = 'geom';
|
|
23
|
+
const table = data.table_name;
|
|
24
|
+
const filterData = query.filter ? await getFilterSQL({
|
|
25
|
+
filter: query.filter, table, filterList: data.filter_list,
|
|
26
|
+
}) : {};
|
|
27
|
+
|
|
28
|
+
// meta
|
|
29
|
+
const metaTable = await getMeta({ pg, table });
|
|
30
|
+
if (metaTable.error) { return metaTable; }
|
|
31
|
+
const { pk: pkey, columns } = metaTable;
|
|
32
|
+
|
|
33
|
+
// props
|
|
34
|
+
const columnsFiltered = columns.filter(el => !['json', 'geometry'].includes(pg.pgType[el.dataTypeID]) && !['uid', 'cdate', 'editor_id', 'editor_date'].includes(el.name));
|
|
35
|
+
const props = columnsFiltered.map(el => {
|
|
36
|
+
return el.type?.[0] === '_' ? `${el.name}[1] as ${el.name}` : `${el.name}${['int4'].includes(el.type) ? '::text' : ''}`;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const geomCol = (data?.style?.type === 'point' ? `ST_Centroid(${geom})` : null)
|
|
40
|
+
|| (parseInt(z, 10) < parseInt(query.pointZoom || data?.style?.pointZoom || data?.style?.iconZoom || '0', 10) ? `ST_Centroid(${geom})` : geom);
|
|
41
|
+
|
|
42
|
+
const koef = {
|
|
43
|
+
10: 0.1, 11: 0.05, 12: 0.005, 13: 0.001, 14: 0.001, 15: 0.0005,
|
|
44
|
+
}[z] || 0.0005;
|
|
45
|
+
|
|
46
|
+
const { type } = query;
|
|
47
|
+
const types = { point: 'ST_Point' /* ,ST_MultiPoint */, polygon: 'ST_Polygon,ST_MultiPolygon' };
|
|
48
|
+
const sql = ((query.clusterZoom - z) > 2
|
|
49
|
+
? `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
50
|
+
FROM (
|
|
51
|
+
SELECT floor(random() * 100000 + 1)::int + row_number() over() as row, point_count, ST_AsMVTGeom(st_transform(geom,3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
|
|
52
|
+
FROM (
|
|
53
|
+
SELECT st_centroid(st_union(geom)) as geom, count(*) as point_count
|
|
54
|
+
FROM ${table} where ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d} ) j
|
|
55
|
+
)q`: null
|
|
56
|
+
) || ((query.clusterZoom - z) > 0 ?
|
|
57
|
+
`SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
58
|
+
FROM (
|
|
59
|
+
SELECT floor(random() * 100000 + 1)::int +row_number() over() as row, count(*) as point_count, ST_AsMVTGeom(st_transform(st_centroid(ST_Union(geom)),3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
|
|
60
|
+
FROM (
|
|
61
|
+
SELECT geom, ST_ClusterDBSCAN(geom,${koef},1) OVER () AS cluster
|
|
62
|
+
FROM ${table} where ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d} ) j
|
|
63
|
+
WHERE cluster IS NOT NULL
|
|
64
|
+
GROUP BY cluster
|
|
65
|
+
ORDER BY 1 DESC
|
|
66
|
+
)q`
|
|
67
|
+
|
|
68
|
+
: `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
69
|
+
FROM (
|
|
70
|
+
SELECT
|
|
71
|
+
|
|
72
|
+
floor(random() * 100000 + 1)::int + row_number() over() as row,
|
|
73
|
+
|
|
74
|
+
${props?.length ? `${props.map(el => `"${el}"`).join(',')},` : ''}
|
|
75
|
+
|
|
76
|
+
${pkey} as id,
|
|
77
|
+
ST_AsMVTGeom(st_transform(${geomCol},3857),ST_TileEnvelope(${z},${y},${x})::box2d,4096,256,false) geom
|
|
78
|
+
|
|
79
|
+
FROM (select * from ${table} where ${data.query || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d}
|
|
80
|
+
|
|
81
|
+
and ${geom} is not null and st_srid(${geom}) >0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
${types[type] ? ` and ST_GeometryType(geom) = any ('{ ${types[type]} }') ` : ''}
|
|
86
|
+
|
|
87
|
+
and ${data?.query || 'true'} and ${filterData?.q || 'true'} and ${data?.filter || '1=1'}
|
|
88
|
+
|
|
89
|
+
${(data?.style?.type || data?.geometry_type) === 'polygon' ? `order by st_area(st_transform(${geom},3857)) desc` : ''}
|
|
90
|
+
|
|
91
|
+
limit 3000)q
|
|
92
|
+
) q`);
|
|
93
|
+
|
|
94
|
+
if (query.sql === '1') { return sql; }
|
|
95
|
+
const tile = await pg.query(sql);
|
|
96
|
+
const buffer = Buffer.concat(tile.rows.map((el) => Buffer.from(el.tile)));
|
|
97
|
+
return reply.headers(headers).send(buffer);
|
|
98
|
+
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import fp from 'fastify-plugin';
|
|
2
|
-
// import config from '../config.js';
|
|
3
|
-
|
|
4
|
-
import mapnik from './funcs/mapnik.js';
|
|
5
|
-
import gdalWrapper from './funcs/gdalWrapper.js';
|
|
6
|
-
|
|
7
|
-
async function plugin(fastify, opts) {
|
|
8
|
-
// fastify.decorate('mapnik', mapnik);
|
|
9
|
-
// fastify.decorate('gdalWrapper', gdalWrapper);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default fp(plugin);
|