@opengis/gis 0.2.1 → 0.2.3
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/dist/index.css +1 -1
- package/dist/index.js +4617 -3764
- package/dist/index.umd.cjs +57 -37
- package/module/test/layer/bp1.yml +33 -0
- package/module/test/layer/individual.yml +54 -0
- package/module/test/map/addr.yml +21 -0
- package/module/test/map/bp_myo.json +15 -12
- package/module/test/map/bpf.json +44 -0
- package/module/test/map/mbd.json +13 -13
- package/module/test/map/ts.json +15 -11
- package/package.json +11 -5
- package/plugin.js +4 -2
- package/server/plugins/vite.js +3 -7
- package/server/routes/gis/services/get.services.col.js +19 -18
- package/server/routes/gis/services/get.services.js +60 -55
- package/server/routes/map/controllers/layerList.js +42 -32
- package/server/routes/map/controllers/mapFormat.js +76 -116
- package/server/routes/map/maps/get.map.js +7 -4
- package/server/routes/map/vtile1.js +76 -94
- package/module/test/map/address/addr.yml +0 -6
- package/module/test/map/address/index.yml +0 -22
- package/module/test/map/address/street.yml +0 -16
- package/module/test/map/address2/addr.json +0 -9
- package/module/test/map/address2/index.json +0 -35
- package/module/test/map/address2/street.json +0 -19
- package/module/test/map/address3.yml +0 -52
- package/module/test/map/address4.json +0 -34
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
config, pgClients, yml2json, getTemplates, getTemplate,
|
|
3
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
4
|
|
|
3
5
|
export default async function layerList({
|
|
4
|
-
|
|
6
|
+
pg = pgClients.client, query = {}, user = {},
|
|
5
7
|
}, reply) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const { sql } = query;
|
|
9
|
+
const layers = getTemplates('layer');
|
|
10
|
+
const files = Promise.all(layers.map(async (el) => {
|
|
11
|
+
const layer = await getTemplate('layer', el[0]);
|
|
12
|
+
return layer;
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
if (!pg.pk?.['gis.services']) {
|
|
16
|
+
return files;
|
|
17
|
+
// return reply.status(404).send('services table not found');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const q = `
|
|
13
21
|
select service_id as id, name, category, style, bbox::box2d as extent, st_asgeojson(bbox)::json as geom, null as url, coalesce(service_type, 'vtile') as service, group_id,
|
|
14
22
|
popup, card, filters, style, source_path
|
|
15
23
|
from gis.services where is_active and ${!user.uid ? 'is_public' : '1=1'}
|
|
@@ -19,32 +27,34 @@ export default async function layerList({
|
|
|
19
27
|
from gis.ogc_service where enabled and ${!user.uid ? 'ispublic' : '1=1'}
|
|
20
28
|
`;
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
if (user.uid && sql) return q;
|
|
31
|
+
|
|
32
|
+
const rows = await pg.query(q).then(el => el.rows || []);
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
const totals = pg.queryCache ? await pg.queryCache('select json_object_agg(oid::regclass, reltuples) from pg_class')
|
|
35
|
+
.then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
36
|
+
rows.filter(row => row.source_path).forEach(row => Object.assign(row, { count: totals[row.source_path] || 0 }));
|
|
25
37
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
const groupIds = rows.map(el => el.group_id).filter(Boolean);
|
|
39
|
+
const groupNames = groupIds.length ? await pg.query('select json_object_agg(group_id,group_name) from gis.group_list where group_id=any($1)', [groupIds]).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
40
|
+
rows.filter(el => el.group_id).forEach(row => Object.assign(row, { group_name: groupNames[row.group_id] }));
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
if (!rows.length) {
|
|
43
|
+
return reply.status(200).send([]);
|
|
44
|
+
}
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
// parse service style
|
|
47
|
+
rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : null }));
|
|
48
|
+
// assign service url
|
|
49
|
+
rows.filter(row => row.service !== 'ogc').forEach(row => Object.assign(row, { url: `${config.prefix || '/api'}/vtile/${row.id}/ua/{z}/{x}/{y}.vmt` }));
|
|
50
|
+
// parse extent string to number[]
|
|
51
|
+
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
52
|
+
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
53
|
+
?.replace?.(/ /g, ',')
|
|
54
|
+
?.split?.(','),
|
|
55
|
+
}));
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : null }));
|
|
40
|
-
// assign service url
|
|
41
|
-
rows.filter(row => row.service !== 'ogc').forEach(row => Object.assign(row, { url: `${config.prefix || '/api'}/vtile/${row.id}/ua/{z}/{x}/{y}.vmt` }));
|
|
42
|
-
// parse extent string to number[]
|
|
43
|
-
rows.filter(row => row.extent).forEach(row => Object.assign(row, {
|
|
44
|
-
extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
|
|
45
|
-
?.replace?.(/ /g, ",")
|
|
46
|
-
?.split?.(",")
|
|
47
|
-
}));
|
|
57
|
+
// return files;
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
}
|
|
59
|
+
return reply.status(200).send(rows.concat(files));
|
|
60
|
+
}
|
|
@@ -1,125 +1,85 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
pgClients, getTemplate, handlebars, metaFormat,
|
|
3
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
4
|
|
|
3
5
|
export default async function mapFormat(req, reply) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const columns = card;
|
|
54
|
-
if (!source_path) return reply.status(404).send('missing source_path');
|
|
55
|
-
|
|
56
|
-
const pk = pg.pk?.[source_path];
|
|
57
|
-
if (!pk) return reply.status(404).send('missing pk');
|
|
58
|
-
|
|
59
|
-
if (!columns) return reply.status(404).send('columns setting not found');
|
|
60
|
-
|
|
61
|
-
const columnNames = columns.map(col => col.name);
|
|
62
|
-
const excluded = ["created_by", "created_at", "updated_by", "geom", "id", "uid", "updated_at", "cdate", "editor_date", "editor_id"];
|
|
63
|
-
const filteredColumns = columnNames.filter(name => !excluded.includes(name));
|
|
64
|
-
|
|
65
|
-
const rows = await pg.query(
|
|
66
|
-
`SELECT ${pk} as "id", geom::json, ${filteredColumns.map(n => `"${n}"`).join(", ")} FROM ${source_path} WHERE ${pk} = $1`,
|
|
67
|
-
[id]
|
|
68
|
-
).then(el => el.rows || []);
|
|
69
|
-
|
|
70
|
-
if (!rows.length) return reply.status(404).send('object not found');
|
|
71
|
-
|
|
72
|
-
const classifiers = columns
|
|
73
|
-
.filter(col => col.data && ["select", "badge", "tags"].includes(col.format))
|
|
74
|
-
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
75
|
-
|
|
76
|
-
await metaFormat({ rows, table: source_path, cls: classifiers, sufix: false });
|
|
77
|
-
const fullRow = rows[0];
|
|
78
|
-
|
|
79
|
-
const result = [];
|
|
80
|
-
for await (const col of columns) {
|
|
81
|
-
if (excluded.includes(col.name)) continue;
|
|
82
|
-
if (col.hidden_card === true) continue;
|
|
83
|
-
|
|
84
|
-
const name = col.label || col.ua || col.name;
|
|
85
|
-
let value;
|
|
86
|
-
value = fullRow[`${col.name}_data`]?.text
|
|
6
|
+
const { pg = pgClients.client, query = {} } = req;
|
|
7
|
+
const { layer, id } = query;
|
|
8
|
+
const time = Date.now();
|
|
9
|
+
|
|
10
|
+
if (!layer || !id) return reply.status(404).send('not enough params: layer,id,map is required');
|
|
11
|
+
|
|
12
|
+
const service = await getTemplate('layer', layer) || (pg.tlist.includes('gis.services') ? await pg.query('SELECT * FROM gis.services WHERE service_id = $1', [layer]).then(res => res.rows[0]) : null);
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
source_path: tname, cardInterface, card, template,
|
|
16
|
+
} = service;
|
|
17
|
+
|
|
18
|
+
const columns = card;
|
|
19
|
+
if (!tname) return reply.status(404).send('missing source_path');
|
|
20
|
+
|
|
21
|
+
const pk = pg.pk?.[tname];
|
|
22
|
+
if (!pk) return reply.status(404).send('missing pk');
|
|
23
|
+
|
|
24
|
+
if (!columns) return reply.status(404).send('columns setting not found');
|
|
25
|
+
|
|
26
|
+
const columnNames = columns.map(col => col.name);
|
|
27
|
+
const excluded = ['created_by', 'created_at', 'updated_by', 'geom', 'id', 'uid', 'updated_at', 'cdate', 'editor_date', 'editor_id'];
|
|
28
|
+
const filteredColumns = columnNames.filter(name => !excluded.includes(name));
|
|
29
|
+
|
|
30
|
+
const rows = await pg.query(
|
|
31
|
+
`SELECT ${pk} as "id", geom::json, ${filteredColumns.map(n => `"${n}"`).join(', ')} FROM ${tname} WHERE ${pk} = $1`,
|
|
32
|
+
[id],
|
|
33
|
+
).then(el => el.rows || []);
|
|
34
|
+
|
|
35
|
+
if (!rows.length) return reply.status(404).send('object not found');
|
|
36
|
+
|
|
37
|
+
const classifiers = columns
|
|
38
|
+
.filter(col => col.data && ['select', 'badge', 'tags'].includes(col.format))
|
|
39
|
+
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
40
|
+
|
|
41
|
+
await metaFormat({
|
|
42
|
+
rows, table: tname, cls: classifiers, sufix: false,
|
|
43
|
+
});
|
|
44
|
+
const fullRow = rows[0];
|
|
45
|
+
|
|
46
|
+
const result = [];
|
|
47
|
+
const filtered = columns.filter(col => !excluded.includes(col.name));
|
|
48
|
+
for (let i = 0; i < filtered.length; i += 1) {
|
|
49
|
+
const col = filtered[i];
|
|
50
|
+
|
|
51
|
+
const name = col.label || col.ua || col.name;
|
|
52
|
+
const value = (col.format === 'date' ? new Date(fullRow[col.name]).toLocaleDateString('uk-UA') : null) || fullRow[`${col.name}_data`]?.text
|
|
87
53
|
|| fullRow[`${col.name}_text`]
|
|
88
54
|
|| fullRow[col.name];
|
|
89
55
|
|
|
90
|
-
|
|
91
|
-
// const dt = formatDate(fullRow[col.name], { hash: { format: 'dd.mm.yy' } });
|
|
92
|
-
const dt = await handlebars.compile(`{{formatDate "${fullRow[col.name]}"}}`)({ format: 'dd.mm.yy' });
|
|
93
|
-
value = dt;
|
|
94
|
-
}
|
|
95
|
-
if (!value) continue;
|
|
96
|
-
result.push(`<div class="grid grid-cols-1 gap-1 py-3 sm:grid-cols-3 sm:gap-4 even:bg-gray-50 text-[12px]">
|
|
56
|
+
result.push(`<div class="grid grid-cols-1 gap-1 py-3 sm:grid-cols-3 sm:gap-4 even:bg-gray-50 text-[12px]">
|
|
97
57
|
<dt class="text-gray-900">${name}</dt>
|
|
98
58
|
<dd class="text-gray-700 sm:col-span-2">${value || '-'}</dd>
|
|
99
59
|
</div>`);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const htmlTemplate = pg?.pk?.['admin.template']
|
|
63
|
+
? await pg.query('select body from admin.templates where name=$1 limit 1', [template || id]).then(el => el.rows?.[0]?.body)
|
|
64
|
+
: null;
|
|
65
|
+
|
|
66
|
+
const html1 = await handlebars.compile(htmlTemplate || 'template not found')(fullRow);
|
|
67
|
+
|
|
68
|
+
const html = template
|
|
69
|
+
? html1
|
|
70
|
+
: `<dl class="divide-y divide-gray-100 py-[5px]">${result.join('')}</dl>`;
|
|
71
|
+
|
|
72
|
+
const res = {
|
|
73
|
+
time: Date.now() - time,
|
|
74
|
+
id,
|
|
75
|
+
rows: fullRow,
|
|
76
|
+
columns,
|
|
77
|
+
template,
|
|
78
|
+
html,
|
|
79
|
+
};
|
|
80
|
+
if (service) {
|
|
81
|
+
res.cardInterface = cardInterface;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return res;
|
|
125
85
|
}
|
|
@@ -31,7 +31,10 @@ export default async function getMap({ params = {}, pg = pgClients.client }, rep
|
|
|
31
31
|
|
|
32
32
|
const totals = pg.queryCache ? await pg.queryCache(`select json_object_agg(oid::regclass, reltuples) from pg_class`)
|
|
33
33
|
.then(el => el.rows?.[0]?.json_object_agg || {}) : {};
|
|
34
|
-
|
|
34
|
+
const maps = pg.pk?.['gis.maps'] ? await pg.query(
|
|
35
|
+
`SELECT map_id as slug, name FROM gis.maps`).then(el => el.rows || []) : [];
|
|
36
|
+
|
|
37
|
+
|
|
35
38
|
if (params.id) {
|
|
36
39
|
const map = rows[0] || {};
|
|
37
40
|
const loadTemplate = await getTemplate('map', params.id) || await getTemplate('map', map.map_key);
|
|
@@ -43,13 +46,13 @@ export default async function getMap({ params = {}, pg = pgClients.client }, rep
|
|
|
43
46
|
const layerData = await getTemplate('layer', layer);
|
|
44
47
|
const serviceData = layerData || await pg.query('select service_id as id, *, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center from gis.services where service_id=$1', [layer]).then(el => el.rows?.[0]);
|
|
45
48
|
Object.assign(serviceData, { count: totals[serviceData.source_path || ''] || 0 });
|
|
46
|
-
serviceData.style = yaml.load(serviceData.style);
|
|
49
|
+
serviceData.style = typeof serviceData.style ==='object'?serviceData.style: yaml.load(serviceData.style);
|
|
47
50
|
return { ...serviceData, id: layer, visible: true };
|
|
48
51
|
}));
|
|
49
|
-
return {
|
|
52
|
+
return { maps,...rows[0], ...obj, layers };
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
return reply.status(200).send({ ...rows[0], ...loadTemplate });
|
|
55
|
+
return reply.status(200).send({ maps, ...rows[0], ...loadTemplate });
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
if (params.id && !rows.length) {
|
|
@@ -1,107 +1,89 @@
|
|
|
1
1
|
const headers = {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
'Content-Type': 'application/x-protobuf',
|
|
3
|
+
'Cache-Control': 'no-cache',
|
|
4
4
|
};
|
|
5
5
|
import Sphericalmercator from '@mapbox/sphericalmercator';
|
|
6
|
+
|
|
6
7
|
const mercator = new Sphericalmercator({ size: 256 });
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
getColumnCLS, getTemplate, getMeta, getFilterSQL, getSelect,
|
|
10
|
+
} from '@opengis/fastify-table/utils.js';
|
|
8
11
|
import yaml from 'js-yaml';
|
|
9
12
|
|
|
10
13
|
const propsCache = {};
|
|
11
14
|
|
|
12
|
-
export default async function vtile({
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
if (type === 'select' && sql) {
|
|
68
|
-
const { fields = [] } = await pg.query(sql + ' limit 0');
|
|
69
|
-
return `(select "${fields[1].name}" from (${sql})s${idx} where "${fields[0].name}"="${key}" limit 1) as "${key}_text","${key}"::text`
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (obj[key]) {
|
|
73
|
-
const clsdata = await pg.query('select name, type, data as sql from admin.cls where name=$1', [obj[key]]).then(el => el.rows?.[0] || {});
|
|
74
|
-
if (clsdata.name && clsdata.type === 'json') {
|
|
75
|
-
return `(select name from admin.cls where parent='${clsdata.name}' and code::text="${key}"::text limit 1) as "${key}_text","${key}"::text`;
|
|
76
|
-
}
|
|
77
|
-
if (clsdata.type === 'sql' && clsdata.sql) {
|
|
78
|
-
const { fields = [] } = await pg.query(clsdata.sql + ' limit 0');
|
|
79
|
-
return `(select "${fields[1].name}" from (${clsdata.sql})s${idx} where "${fields[0].name}"="${key}" limit 1) as "${key}_text","${key}"::text`
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return `"${key}"::text`;
|
|
83
|
-
}));
|
|
84
|
-
if (!propsCache[layer]) { propsCache[layer] = propsWithCls; }
|
|
85
|
-
|
|
86
|
-
const geomCol = (style?.type === 'point' ? `ST_Centroid(${geom})` : null)
|
|
15
|
+
export default async function vtile({
|
|
16
|
+
params = {}, query, pg, user,
|
|
17
|
+
}, reply) {
|
|
18
|
+
const { y, z } = params;
|
|
19
|
+
const x = params.x.split('.')[0] - 0;
|
|
20
|
+
|
|
21
|
+
// layer
|
|
22
|
+
const [map, layer] = params.layer.includes(':') ? params.layer.split(':') : [null, params.layer];
|
|
23
|
+
|
|
24
|
+
// service
|
|
25
|
+
const data = await getTemplate('layer', layer) || await pg.query(`select * from gis.services where is_active and ${!user?.uid ? 'is_public' : '1=1'} and service_id=$1`, [layer]).then(el => el.rows?.[0]);
|
|
26
|
+
|
|
27
|
+
const geom = data?.geometry_column || 'geom';
|
|
28
|
+
const table = data?.source_path;
|
|
29
|
+
const style = typeof data?.style === 'object' ? data?.style : yaml.load(data?.style);
|
|
30
|
+
const filterList = data?.filters;
|
|
31
|
+
const layerQuery = data?.query;
|
|
32
|
+
|
|
33
|
+
// bbox
|
|
34
|
+
const bbox = mercator.bbox(+y, +x, +z, false/* , '900913' */);
|
|
35
|
+
const bbox2d = `'BOX(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d`;
|
|
36
|
+
|
|
37
|
+
const filterData = query.filter ? await getFilterSQL({
|
|
38
|
+
filter: query.filter, table, filterList,
|
|
39
|
+
}) : {};
|
|
40
|
+
|
|
41
|
+
// meta
|
|
42
|
+
const metaTable = await getMeta({ pg, table });
|
|
43
|
+
if (metaTable.error) { return metaTable; }
|
|
44
|
+
const { pk: pkey, columns } = metaTable;
|
|
45
|
+
|
|
46
|
+
// props
|
|
47
|
+
const props = !query.all ? data.popup || [] : columns.filter(el => !['json', 'geometry'].includes(pg.pgType[el.dataTypeID]) && !['uid', 'cdate', 'editor_id', 'editor_date'].includes(el.name));
|
|
48
|
+
const cache = layer + (query.all ? '-all' : '');
|
|
49
|
+
const propsWithCls = propsCache[cache] ?? await Promise.all(props.map(async (col, idx) => {
|
|
50
|
+
const key = col.name;
|
|
51
|
+
const select = data.popup?.find(el => el.name === key);
|
|
52
|
+
// console.log(select);
|
|
53
|
+
const clsData = select?.data || col.data;
|
|
54
|
+
const cls = clsData ? await getSelect(clsData).then(el => ({ name: clsData, type: el.arr ? 'cls' : 'select', sql: el.sql })) : null;
|
|
55
|
+
const { name, type, sql } = cls || getColumnCLS(table, col.data || key) || {};
|
|
56
|
+
// console.log({ name, type, sql });
|
|
57
|
+
if (name && type === 'cls') {
|
|
58
|
+
return `(select name from admin.cls where parent='${name}' and code::text=${key}::text limit 1) as "${key}_text","${key}"::text`;
|
|
59
|
+
}
|
|
60
|
+
if (type === 'select' && sql) {
|
|
61
|
+
const { fields = [] } = await pg.query(`${sql} limit 0`);
|
|
62
|
+
return `(select "${fields[1].name}" from (${sql})s${idx} where "${fields[0].name}"::text="${key}"::text limit 1) as "${key}_text","${key}"::text`;
|
|
63
|
+
}
|
|
64
|
+
return `"${key}"::text`;
|
|
65
|
+
}));
|
|
66
|
+
propsCache[cache] = propsCache[cache] || propsWithCls;
|
|
67
|
+
|
|
68
|
+
const geomCol = (style?.type === 'point' ? `ST_Centroid(${geom})` : null)
|
|
87
69
|
|| (parseInt(z, 10) < parseInt(query.pointZoom || style?.pointZoom || style?.iconZoom || '0', 10) ? `ST_Centroid(${geom})` : geom);
|
|
88
70
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
const koef = {
|
|
72
|
+
10: 0.1, 11: 0.05, 12: 0.005, 13: 0.001, 14: 0.001, 15: 0.0005,
|
|
73
|
+
}[z] || 0.0005;
|
|
92
74
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
75
|
+
const { type } = query;
|
|
76
|
+
const types = { point: 'ST_Point' /* ,ST_MultiPoint */, polygon: 'ST_Polygon,ST_MultiPolygon' };
|
|
77
|
+
const sql = ((query.clusterZoom - z) > 2
|
|
78
|
+
? `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
97
79
|
FROM (
|
|
98
80
|
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
|
|
99
81
|
FROM (
|
|
100
82
|
SELECT st_centroid(st_union(geom)) as geom, count(*) as point_count
|
|
101
83
|
FROM ${table} where ${layerQuery || 'true'} and ${filterData?.q || 'true'} and ${geom} && ${bbox2d} ) j
|
|
102
|
-
)q
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
)q` : null
|
|
85
|
+
) || ((query.clusterZoom - z) > 0
|
|
86
|
+
? `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
105
87
|
FROM (
|
|
106
88
|
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
|
|
107
89
|
FROM (
|
|
@@ -112,7 +94,7 @@ export default async function vtile({ params = {}, query, pg, user }, reply) {
|
|
|
112
94
|
ORDER BY 1 DESC
|
|
113
95
|
)q`
|
|
114
96
|
|
|
115
|
-
|
|
97
|
+
: `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
|
|
116
98
|
FROM (
|
|
117
99
|
SELECT
|
|
118
100
|
|
|
@@ -138,8 +120,8 @@ export default async function vtile({ params = {}, query, pg, user }, reply) {
|
|
|
138
120
|
limit 3000)q
|
|
139
121
|
) q`);
|
|
140
122
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
123
|
+
if (query.sql === '1') { return sql; }
|
|
124
|
+
const tile = await pg.query(sql);
|
|
125
|
+
const buffer = Buffer.concat(tile.rows.map((el) => Buffer.from(el.tile)));
|
|
126
|
+
return reply.headers(headers).send(buffer);
|
|
127
|
+
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: address
|
|
3
|
-
name: address
|
|
4
|
-
title: Адресний реєстр
|
|
5
|
-
description: Адресний реєстр
|
|
6
|
-
center:
|
|
7
|
-
- 30.5234
|
|
8
|
-
- 50.4501
|
|
9
|
-
zoom: 12
|
|
10
|
-
basemap: osm
|
|
11
|
-
sources: []
|
|
12
|
-
widgets:
|
|
13
|
-
- type: legend
|
|
14
|
-
position: bottom-right
|
|
15
|
-
config:
|
|
16
|
-
items:
|
|
17
|
-
- label: Житлова зона
|
|
18
|
-
color: "#4caf50"
|
|
19
|
-
- label: Комерційна зона
|
|
20
|
-
color: "#2196f3"
|
|
21
|
-
- label: Промислова зона
|
|
22
|
-
color: "#f44336"
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
label: Вулиці
|
|
2
|
-
source_path: data_address.street.table
|
|
3
|
-
style:
|
|
4
|
-
attribute: type
|
|
5
|
-
colors:
|
|
6
|
-
"1": "#4caf50"
|
|
7
|
-
"2": "#2196f3"
|
|
8
|
-
"3": "#f44336"
|
|
9
|
-
"4": "#4caf50"
|
|
10
|
-
"5": "#2196f3"
|
|
11
|
-
"6": "#f44336"
|
|
12
|
-
"8": "#4caf50"
|
|
13
|
-
"9": "#2196f3"
|
|
14
|
-
"11": "#f44336"
|
|
15
|
-
"16": "#4caf50"
|
|
16
|
-
visible: true
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "address3",
|
|
3
|
-
"name": "address",
|
|
4
|
-
"title": "Адресний реєстр",
|
|
5
|
-
"description": "Адресний реєстр",
|
|
6
|
-
"center": [
|
|
7
|
-
30.5234,
|
|
8
|
-
50.4501
|
|
9
|
-
],
|
|
10
|
-
"zoom": 12,
|
|
11
|
-
"basemap": "osm",
|
|
12
|
-
"sources": [],
|
|
13
|
-
"widgets": [
|
|
14
|
-
{
|
|
15
|
-
"type": "legend",
|
|
16
|
-
"position": "bottom-right",
|
|
17
|
-
"config": {
|
|
18
|
-
"items": [
|
|
19
|
-
{
|
|
20
|
-
"label": "Житлова зона",
|
|
21
|
-
"color": "#4caf50"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"label": "Комерційна зона",
|
|
25
|
-
"color": "#2196f3"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"label": "Промислова зона",
|
|
29
|
-
"color": "#f44336"
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"label": "Вулиці",
|
|
3
|
-
"source_path": "data_address.street.table",
|
|
4
|
-
"style": {
|
|
5
|
-
"attribute": "type",
|
|
6
|
-
"colors": {
|
|
7
|
-
"1": "#4caf50",
|
|
8
|
-
"2": "#2196f3",
|
|
9
|
-
"3": "#f44336",
|
|
10
|
-
"4": "#4caf50",
|
|
11
|
-
"5": "#2196f3",
|
|
12
|
-
"6": "#f44336",
|
|
13
|
-
"8": "#4caf50",
|
|
14
|
-
"9": "#2196f3",
|
|
15
|
-
"11": "#f44336",
|
|
16
|
-
"16": "#4caf50"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|