@opengis/gis 0.2.20 → 0.2.22
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/README.md +5 -5
- package/dist/index.css +1 -1
- package/dist/index.js +1691 -1663
- package/dist/index.umd.cjs +20 -20
- package/module/cls.json +6 -6
- package/module/gis/card/gis.maps.table/index.yml +14 -14
- package/module/gis/card/gis.maps.table/main_info.hbs +25 -25
- package/module/gis/card/gis.maps.table/maps_layers.hbs +19 -19
- package/module/gis/card/gis.metadata.table/index.yml +22 -22
- package/module/gis/card/gis.metadata.table/main_info.hbs +20 -20
- package/module/gis/card/gis.metadata.table/metadata_info.hbs +27 -27
- package/module/gis/card/gis.metadata.table/other.hbs +25 -25
- package/module/gis/card/gis.rasters.table/index.yml +11 -11
- package/module/gis/card/gis.rasters.table/main_info.hbs +27 -27
- package/module/gis/card/gis.registers.table/cls.hbs +36 -36
- package/module/gis/card/gis.registers.table/columns.hbs +89 -89
- package/module/gis/card/gis.registers.table/filters.hbs +80 -80
- package/module/gis/card/gis.registers.table/index.yml +23 -23
- package/module/gis/card/gis.registers.table/main_info.hbs +35 -35
- package/module/gis/card/gis.registers.table/source.hbs +45 -45
- package/module/gis/card/gis.services.table/attributes.hbs +91 -91
- package/module/gis/card/gis.services.table/filters.hbs +83 -83
- package/module/gis/card/gis.services.table/index.yml +25 -25
- package/module/gis/card/gis.services.table/main_info.hbs +27 -27
- package/module/gis/card/gis.services.table/source.hbs +25 -25
- package/module/gis/cls/bool.yes_no.json +12 -12
- package/module/gis/cls/encoding.json +14 -14
- package/module/gis/cls/geom_type.json +14 -14
- package/module/gis/cls/gis.column_type.json +34 -34
- package/module/gis/cls/gis.column_view_type.json +26 -26
- package/module/gis/cls/gis.filter_type.json +22 -22
- package/module/gis/cls/language.json +10 -10
- package/module/gis/cls/meta.service_type.json +42 -42
- package/module/gis/cls/ogc.service.json +21 -21
- package/module/gis/cls/service_type.json +42 -42
- package/module/gis/cls/source_type.json +10 -10
- package/module/gis/cls/standarts.json +6 -6
- package/module/gis/cls/topic_category.json +106 -106
- package/module/gis/cls/update_frequency.json +29 -29
- package/module/gis/cls/view.json +21 -21
- package/module/gis/form/gis.cartocss.form.json +46 -0
- package/module/gis/form/gis.group_list.form.json +17 -17
- package/module/gis/form/gis.maps.form.json +64 -64
- package/module/gis/form/gis.metadata.form.json +240 -240
- package/module/gis/form/gis.ogc_service.form.json +40 -40
- package/module/gis/form/gis.rasters.form.json +99 -99
- package/module/gis/form/gis.registers.form.json +110 -110
- package/module/gis/form/gis.registers_column.form.json +84 -84
- package/module/gis/form/gis.registers_filter.form.json +65 -65
- package/module/gis/form/gis.services.form.json +120 -120
- package/module/gis/form/gis.services_attributes.form.json +75 -75
- package/module/gis/form/gis.services_filter.form.json +65 -65
- package/module/gis/menu.json +43 -43
- package/module/gis/select/pg.columns.parent.sql +6 -6
- package/module/gis/select/pg.table_name.sql +17 -17
- package/module/gis/select/service_id.sql +1 -1
- package/module/gis/table/gis.cartocss.table.json +61 -0
- package/module/gis/table/gis.group_list.table.json +35 -35
- package/module/gis/table/gis.maps.table.json +69 -69
- package/module/gis/table/gis.metadata.table.json +70 -70
- package/module/gis/table/gis.ogc_service.table.json +97 -97
- package/module/gis/table/gis.rasters.table.json +97 -97
- package/module/gis/table/gis.registers.table.json +79 -79
- package/module/gis/table/gis.services.table.json +99 -99
- package/module/gis/table/site.gis.registers.table.json +88 -88
- package/module/gis/table/site.gis.services.table.json +106 -106
- package/module/gis/templates/ISO19136_2017_gml_template.xml +330 -330
- package/module/gis/tokens.yml +5 -5
- package/module/test/cls/bp_build_type.json +37 -37
- package/module/test/cls/doc_status.json +31 -31
- package/module/test/cls/ts.temp_status.json +18 -18
- package/module/test/cls/ts.temp_structure.ts_class.json +49 -49
- package/module/test/cls/ts.temp_type.json +9 -9
- package/module/test/layer/bp.json +59 -59
- package/module/test/layer/bp1.yml +33 -33
- package/module/test/layer/individual.yml +53 -53
- package/module/test/layer/ts.linking_passport.yml +55 -55
- package/module/test/layer/ts.temp_structure.yml +50 -50
- package/module/test/map/addr.yml +21 -21
- package/module/test/map/bp_myo.json +43 -43
- package/module/test/map/bpf.json +43 -43
- package/module/test/map/main.json +36 -36
- package/module/test/map/mbd.json +91 -91
- package/module/test/map/ts.json +52 -52
- package/module/test/select/address_id.json +2 -2
- package/module/test/select/address_id.sql +7 -7
- package/module/test/select/core.user_uid.sql +1 -1
- package/module/test/table/data_address.street.table.json +69 -69
- package/module/test/table/data_bp_myo.bp.table.json +122 -122
- package/package.json +69 -69
- package/plugin.js +44 -44
- package/server/migrations/maps.sql +30 -30
- package/server/migrations/ogc.sql +106 -106
- package/server/migrations/rasters.sql +263 -263
- package/server/migrations/services.sql +247 -247
- package/server/migrations/widgets.sql +20 -20
- package/server/plugins/crons.js +21 -21
- package/server/plugins/mapnik/funcs/createXML.js +72 -72
- package/server/plugins/mapnik/funcs/gdalWrapper.js +72 -72
- package/server/plugins/mapnik/funcs/map.proto +241 -241
- package/server/plugins/mapnik/funcs/mapnik.js +106 -106
- package/server/plugins/mapnik/funcs/rasterConfig.js +11 -11
- package/server/plugins/mapnik/funcs/rasterExists.js +20 -20
- package/server/plugins/mapnik/funcs/rasterInfo.js +109 -109
- package/server/plugins/mapnik/funcs/rasterVrt.js +55 -55
- package/server/plugins/mapnik/funcs/rasterXML.js +65 -65
- package/server/plugins/mapnik/funcs/rootFolder.mjs +8 -8
- package/server/plugins/mapnik/utils/map.proto +241 -241
- package/server/plugins/vite.js +74 -74
- package/server/routes/gis/dashboard.js +29 -0
- package/server/routes/gis/index.mjs +61 -59
- package/server/routes/gis/metadata/metadataXML.js +13 -13
- package/server/routes/gis/ogc/map.info.point.js +124 -124
- package/server/routes/gis/registers/add.registry.js +35 -35
- package/server/routes/gis/registers/del.registry.js +14 -14
- package/server/routes/gis/registers/funcs/classifiers.js +100 -100
- package/server/routes/gis/registers/funcs/columns.js +4 -4
- package/server/routes/gis/registers/funcs/content.type.js +9 -9
- package/server/routes/gis/registers/funcs/get.info.js +89 -89
- package/server/routes/gis/registers/funcs/handleRegistryRequest.js +133 -122
- package/server/routes/gis/registers/gis.export.js +148 -148
- package/server/routes/gis/registers/gis.registry.js +70 -38
- package/server/routes/gis/registers/gis.registry.list.js +59 -59
- package/server/routes/gis/registers/insert.columns.js +107 -107
- package/server/routes/gis/registers/insert.filters.js +110 -110
- package/server/routes/gis/registers/map.registry.js +79 -79
- package/server/routes/gis/services/add.service.js +64 -64
- package/server/routes/gis/services/del.service.js +12 -12
- package/server/routes/gis/services/get.layer.geom.js +27 -27
- package/server/routes/gis/services/get.services.col.js +33 -33
- package/server/routes/gis/services/get.services.js +84 -84
- package/server/routes/gis/services/legend.auto.js +77 -77
- package/server/routes/map/controllers/geojson.js +187 -0
- package/server/routes/map/controllers/jsonData.js +205 -0
- package/server/routes/map/controllers/layerList.js +60 -60
- package/server/routes/map/controllers/map.js +123 -123
- package/server/routes/map/controllers/mapCatalog.js +72 -72
- package/server/routes/map/controllers/mapCatalogAttribute.js +55 -55
- package/server/routes/map/controllers/mapFeatures.js +128 -128
- package/server/routes/map/controllers/mapFormat.js +83 -83
- package/server/routes/map/controllers/mapTiles.js +152 -152
- package/server/routes/map/controllers/maps.js +15 -15
- package/server/routes/map/controllers/marker_icon.js +43 -43
- package/server/routes/map/controllers/rtile.js +134 -134
- package/server/routes/map/controllers/vtile.js +172 -172
- package/server/routes/map/index.mjs +142 -129
- package/server/routes/map/maps/add.map.js +41 -41
- package/server/routes/map/maps/del.map.js +18 -18
- package/server/routes/map/maps/get.map.js +86 -86
- package/server/routes/map/vtile1.js +170 -170
- package/server/routes/map/widgets/add.widget.js +38 -38
- package/server/routes/map/widgets/del.widget.js +22 -22
- package/server/routes/map/widgets/get.widget.js +40 -40
- package/server/routes/root.mjs +3 -3
- package/utils.js +11 -11
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import { config, pgClients, yml2json } from "@opengis/fastify-table/utils.js";
|
|
2
|
-
|
|
3
|
-
const { prefix = '/api' } = config;
|
|
4
|
-
|
|
5
|
-
function getBBox(coordinates) {
|
|
6
|
-
return coordinates[0].reduce(
|
|
7
|
-
([minLon, minLat, maxLon, maxLat], [lon, lat]) => [
|
|
8
|
-
Math.min(minLon, lon),
|
|
9
|
-
Math.min(minLat, lat),
|
|
10
|
-
Math.max(maxLon, lon),
|
|
11
|
-
Math.max(maxLat, lat)
|
|
12
|
-
],
|
|
13
|
-
[coordinates[0][0][0], coordinates[0][0][1], coordinates[0][0][0], coordinates[0][0][1]]
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default async function mapCatalog({ pg = pgClients.client }, reply) {
|
|
18
|
-
const { rows: services = [] } = pg.pk?.['gis.services']
|
|
19
|
-
? await pg.query(`select
|
|
20
|
-
service_id as id, name, service_type, service_url as url,
|
|
21
|
-
source_type, source_path, geometry_column, style, layers,
|
|
22
|
-
st_asgeojson(bbox)::json->'coordinates' as bbox,
|
|
23
|
-
st_asgeojson(center)::json->'coordinates' as center,
|
|
24
|
-
popup, card, filters
|
|
25
|
-
from gis.services where is_active and is_public`
|
|
26
|
-
)
|
|
27
|
-
: {};
|
|
28
|
-
|
|
29
|
-
const bboxq = services.filter(el => el.source_path && pg?.pk?.[el.source_path] && !el.bbox).map(el => `update gis.services set bbox = (select st_extent(${el.geometry_column || 'geom'})::geometry from ${el.source_path}) where service_id='${el.id}'`).join(';');
|
|
30
|
-
await pg.query(bboxq).catch(err => console.error(err.toString()));
|
|
31
|
-
|
|
32
|
-
services.filter(row => row.style).map(row => {
|
|
33
|
-
row.style = yml2json(row.style);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
services.filter(el => el.bbox).forEach(el => {
|
|
37
|
-
el.bbox = getBBox(el.bbox);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
services.filter(el => el.source_type === 'database').forEach(el => {
|
|
41
|
-
el.url = `${prefix}/layer-vtile/${el.id}/{z}/{x}/{y}.vmt`;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
const { rows: rasters = [] } = pg.pk?.['gis.rasters']
|
|
45
|
-
? await pg.query(
|
|
46
|
-
`select
|
|
47
|
-
raster_id as id, name, source_type,
|
|
48
|
-
st_asgeojson(bbox):: json -> 'coordinates' as bbox,
|
|
49
|
-
st_asgeojson(center):: json -> 'coordinates' as center
|
|
50
|
-
from gis.rasters where is_active and is_public`
|
|
51
|
-
)
|
|
52
|
-
: {};
|
|
53
|
-
|
|
54
|
-
const { rows: ogc = [] } = pg.pk?.['gis.ogc_service']
|
|
55
|
-
? await pg.query(
|
|
56
|
-
`select
|
|
57
|
-
service_id as id, name, 'raster' as source_type, url
|
|
58
|
-
from gis.ogc_service `
|
|
59
|
-
)
|
|
60
|
-
: {};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
rasters.forEach(el => {
|
|
65
|
-
el.url = `${prefix}/layer-rtile/${el.id}/{z}/{x}/{y}.png`;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
rasters.filter(el => el.bbox).forEach(el => {
|
|
69
|
-
el.bbox = getBBox(el.bbox);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
return reply.status(200).send({ services, rasters: rasters.concat(ogc) });
|
|
1
|
+
import { config, pgClients, yml2json } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
const { prefix = '/api' } = config;
|
|
4
|
+
|
|
5
|
+
function getBBox(coordinates) {
|
|
6
|
+
return coordinates[0].reduce(
|
|
7
|
+
([minLon, minLat, maxLon, maxLat], [lon, lat]) => [
|
|
8
|
+
Math.min(minLon, lon),
|
|
9
|
+
Math.min(minLat, lat),
|
|
10
|
+
Math.max(maxLon, lon),
|
|
11
|
+
Math.max(maxLat, lat)
|
|
12
|
+
],
|
|
13
|
+
[coordinates[0][0][0], coordinates[0][0][1], coordinates[0][0][0], coordinates[0][0][1]]
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default async function mapCatalog({ pg = pgClients.client }, reply) {
|
|
18
|
+
const { rows: services = [] } = pg.pk?.['gis.services']
|
|
19
|
+
? await pg.query(`select
|
|
20
|
+
service_id as id, name, service_type, service_url as url,
|
|
21
|
+
source_type, source_path, geometry_column, style, layers,
|
|
22
|
+
st_asgeojson(bbox)::json->'coordinates' as bbox,
|
|
23
|
+
st_asgeojson(center)::json->'coordinates' as center,
|
|
24
|
+
popup, card, filters
|
|
25
|
+
from gis.services where is_active and is_public`
|
|
26
|
+
)
|
|
27
|
+
: {};
|
|
28
|
+
|
|
29
|
+
const bboxq = services.filter(el => el.source_path && pg?.pk?.[el.source_path] && !el.bbox).map(el => `update gis.services set bbox = (select st_extent(${el.geometry_column || 'geom'})::geometry from ${el.source_path}) where service_id='${el.id}'`).join(';');
|
|
30
|
+
await pg.query(bboxq).catch(err => console.error(err.toString()));
|
|
31
|
+
|
|
32
|
+
services.filter(row => row.style).map(row => {
|
|
33
|
+
row.style = yml2json(row.style);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
services.filter(el => el.bbox).forEach(el => {
|
|
37
|
+
el.bbox = getBBox(el.bbox);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
services.filter(el => el.source_type === 'database').forEach(el => {
|
|
41
|
+
el.url = `${prefix}/layer-vtile/${el.id}/{z}/{x}/{y}.vmt`;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const { rows: rasters = [] } = pg.pk?.['gis.rasters']
|
|
45
|
+
? await pg.query(
|
|
46
|
+
`select
|
|
47
|
+
raster_id as id, name, source_type,
|
|
48
|
+
st_asgeojson(bbox):: json -> 'coordinates' as bbox,
|
|
49
|
+
st_asgeojson(center):: json -> 'coordinates' as center
|
|
50
|
+
from gis.rasters where is_active and is_public`
|
|
51
|
+
)
|
|
52
|
+
: {};
|
|
53
|
+
|
|
54
|
+
const { rows: ogc = [] } = pg.pk?.['gis.ogc_service']
|
|
55
|
+
? await pg.query(
|
|
56
|
+
`select
|
|
57
|
+
service_id as id, name, 'raster' as source_type, url
|
|
58
|
+
from gis.ogc_service `
|
|
59
|
+
)
|
|
60
|
+
: {};
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
rasters.forEach(el => {
|
|
65
|
+
el.url = `${prefix}/layer-rtile/${el.id}/{z}/{x}/{y}.png`;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
rasters.filter(el => el.bbox).forEach(el => {
|
|
69
|
+
el.bbox = getBBox(el.bbox);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return reply.status(200).send({ services, rasters: rasters.concat(ogc) });
|
|
73
73
|
}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { pgClients, getMeta, getSelect, getSelectVal } from "@opengis/fastify-table/utils.js";
|
|
2
|
-
|
|
3
|
-
export default async function mapCatalogAttribute({ pg = pgClients.client, params = {}, query = {} }, reply) {
|
|
4
|
-
const { service, attr } = params;
|
|
5
|
-
if (!service) {
|
|
6
|
-
return reply.status(404).send('not enough params: service');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if (!attr) {
|
|
10
|
-
return reply.status(404).send('not enough params: attr');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (!pg.pk?.['gis.services']) {
|
|
14
|
-
return reply.status(404).send('services table not found');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const source = await pg.query(
|
|
18
|
-
'select source_path from gis.services where service_id=$1 and is_active and is_public',
|
|
19
|
-
[params.service]
|
|
20
|
-
).then(el => el.rows?.[0]?.source_path);
|
|
21
|
-
|
|
22
|
-
if (!source) {
|
|
23
|
-
return reply.status(404).send('service not found');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const cls = await getSelect(query.cls || attr, pg);
|
|
27
|
-
const colname = query.cls ? attr : attr.split(':').pop();
|
|
28
|
-
|
|
29
|
-
if (!colname) {
|
|
30
|
-
return reply.status(400).send('invalid params: attr');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const { columns = [] } = await getMeta({ pg, table: source });
|
|
34
|
-
const { dataTypeID } = columns.find(el => el.name === colname) || {};
|
|
35
|
-
|
|
36
|
-
const q = pg.pgType[dataTypeID]?.includes('[]')
|
|
37
|
-
? `select unnest(${colname})::text as id,count(*) from ${source} group by unnest(${colname}) limit 100`
|
|
38
|
-
: `select ${colname}::text as id,count(*) from ${source} group by ${colname} limit 100`;
|
|
39
|
-
|
|
40
|
-
const countArr = await pg.queryCache(q);
|
|
41
|
-
|
|
42
|
-
const ids = countArr.rows.map(el => el.id);
|
|
43
|
-
|
|
44
|
-
const clsData = await getSelectVal({ pg, values: ids, name: query.cls || attr });
|
|
45
|
-
|
|
46
|
-
const legend = countArr.rows.map(cel => {
|
|
47
|
-
const data = cls?.arr?.find(c => c.id?.toString?.() === cel.id?.toString?.()) || { text: clsData?.[cel.id]?.text || clsData?.[cel.id] };
|
|
48
|
-
return { ...cel, ...data };
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const { min, max } = await pg.queryCache(
|
|
52
|
-
`select min(${attr}), max(${attr}) from ${source} where 1=1`,
|
|
53
|
-
).then(el => { return el.rows?.[0] || {}; });
|
|
54
|
-
|
|
55
|
-
return reply.status(200).send({ legend, min, max });
|
|
1
|
+
import { pgClients, getMeta, getSelect, getSelectVal } from "@opengis/fastify-table/utils.js";
|
|
2
|
+
|
|
3
|
+
export default async function mapCatalogAttribute({ pg = pgClients.client, params = {}, query = {} }, reply) {
|
|
4
|
+
const { service, attr } = params;
|
|
5
|
+
if (!service) {
|
|
6
|
+
return reply.status(404).send('not enough params: service');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (!attr) {
|
|
10
|
+
return reply.status(404).send('not enough params: attr');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!pg.pk?.['gis.services']) {
|
|
14
|
+
return reply.status(404).send('services table not found');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const source = await pg.query(
|
|
18
|
+
'select source_path from gis.services where service_id=$1 and is_active and is_public',
|
|
19
|
+
[params.service]
|
|
20
|
+
).then(el => el.rows?.[0]?.source_path);
|
|
21
|
+
|
|
22
|
+
if (!source) {
|
|
23
|
+
return reply.status(404).send('service not found');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const cls = await getSelect(query.cls || attr, pg);
|
|
27
|
+
const colname = query.cls ? attr : attr.split(':').pop();
|
|
28
|
+
|
|
29
|
+
if (!colname) {
|
|
30
|
+
return reply.status(400).send('invalid params: attr');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { columns = [] } = await getMeta({ pg, table: source });
|
|
34
|
+
const { dataTypeID } = columns.find(el => el.name === colname) || {};
|
|
35
|
+
|
|
36
|
+
const q = pg.pgType[dataTypeID]?.includes('[]')
|
|
37
|
+
? `select unnest(${colname})::text as id,count(*) from ${source} group by unnest(${colname}) limit 100`
|
|
38
|
+
: `select ${colname}::text as id,count(*) from ${source} group by ${colname} limit 100`;
|
|
39
|
+
|
|
40
|
+
const countArr = await pg.queryCache(q);
|
|
41
|
+
|
|
42
|
+
const ids = countArr.rows.map(el => el.id);
|
|
43
|
+
|
|
44
|
+
const clsData = await getSelectVal({ pg, values: ids, name: query.cls || attr });
|
|
45
|
+
|
|
46
|
+
const legend = countArr.rows.map(cel => {
|
|
47
|
+
const data = cls?.arr?.find(c => c.id?.toString?.() === cel.id?.toString?.()) || { text: clsData?.[cel.id]?.text || clsData?.[cel.id] };
|
|
48
|
+
return { ...cel, ...data };
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const { min, max } = await pg.queryCache(
|
|
52
|
+
`select min(${attr}), max(${attr}) from ${source} where 1=1`,
|
|
53
|
+
).then(el => { return el.rows?.[0] || {}; });
|
|
54
|
+
|
|
55
|
+
return reply.status(200).send({ legend, min, max });
|
|
56
56
|
}
|
|
@@ -1,129 +1,129 @@
|
|
|
1
|
-
import { getMeta, getFilterSQL, getTemplate, metaFormat, pgClients, yml2json } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
const layerMetaColumns = ['id', 'name', 'label', 'source', 'table', 'pk', 'geomColumn', 'srid', 'cls', 'htmls'];
|
|
4
|
-
|
|
5
|
-
export default async function mapFeaturesPoint({ pg = pgClients.client, params = {}, query = {} }, reply) {
|
|
6
|
-
const { slug, id } = params;
|
|
7
|
-
const { x, y, sql } = query;
|
|
8
|
-
|
|
9
|
-
if (!slug) {
|
|
10
|
-
return reply.status(400).send('not enough params: slug');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (!(x && y) && !id) {
|
|
14
|
-
return reply.status(400).send('not enough params: xy');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const loadTemplate = await getTemplate('map', slug);
|
|
18
|
-
|
|
19
|
-
if (!loadTemplate) {
|
|
20
|
-
return reply.status(404).send('map not found');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const index = loadTemplate?.find?.(el => el[0].split('.').shift() === 'index')?.[1];
|
|
24
|
-
|
|
25
|
-
const layers1 = !index
|
|
26
|
-
? loadTemplate?.layers
|
|
27
|
-
: loadTemplate?.filter?.(el => el[0].split('.').shift() !== 'index')?.map(el => ({ ...el[1], id: el[0].replace('.yml', '').replace('.json', '') }));
|
|
28
|
-
|
|
29
|
-
const serviceLayers = await Promise.all(layers1.filter(el => typeof el === 'string').map(async (layer) => {
|
|
30
|
-
const layerData = await getTemplate('layer', layer);
|
|
31
|
-
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]);
|
|
32
|
-
serviceData.style = yml2json(serviceData.style);
|
|
33
|
-
return { ...serviceData, id: layer, visible: true };
|
|
34
|
-
}));
|
|
35
|
-
|
|
36
|
-
const layers = layers1.filter(el => el && typeof el === 'object').concat(serviceLayers);
|
|
37
|
-
|
|
38
|
-
if (!layers?.length) {
|
|
39
|
-
return reply.status(404).send('map layers not found');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!layers.filter(el => el.source_path).length) {
|
|
43
|
-
return reply.status(404).send('map layers sources not provided');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const point = `srid=4326;point(${x} ${y})`; // 30, 50
|
|
47
|
-
|
|
48
|
-
const { srids } = await pg.queryCache?.('select json_agg(srid) as srids from spatial_ref_sys').then(el => el.rows?.[0] || {}) || {};
|
|
49
|
-
|
|
50
|
-
await Promise.all(layers.map(async (layer, idx) => {
|
|
51
|
-
const { source_path: source, srid = 4326, id: layerId, name } = layer;
|
|
52
|
-
|
|
53
|
-
const loadTable = await getTemplate('table', source);
|
|
54
|
-
const meta = await getMeta({ pg, table: loadTable?.table || source });
|
|
55
|
-
const { geom = 'geom' } = meta || {};
|
|
56
|
-
const { table = source, columns = meta?.columns } = loadTable || {};
|
|
57
|
-
|
|
58
|
-
const cls = columns
|
|
59
|
-
?.filter(el => el.name && el.data)
|
|
60
|
-
?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
61
|
-
const htmls = columns
|
|
62
|
-
?.filter(el => el.name && el.html)
|
|
63
|
-
?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.html }), {});
|
|
64
|
-
|
|
65
|
-
const pk = pg.pk?.[table] || loadTable?.key;
|
|
66
|
-
|
|
67
|
-
const { optimizedSQL } = await getFilterSQL({ pg, table: source, query: layer?.query });
|
|
68
|
-
|
|
69
|
-
Object.assign(layer, {
|
|
70
|
-
layer: (layerId || name || idx.toString())?.replace?.(/'/g, "''"),
|
|
71
|
-
table,
|
|
72
|
-
pk,
|
|
73
|
-
cls,
|
|
74
|
-
htmls,
|
|
75
|
-
geomColumn: geom,
|
|
76
|
-
optimizedSQL,
|
|
77
|
-
srid,
|
|
78
|
-
step: srids?.includes?.(srid - 0) && srid !== 4326 ? 10 : 0.0002,
|
|
79
|
-
});
|
|
80
|
-
}));
|
|
81
|
-
|
|
82
|
-
const unique = layers
|
|
83
|
-
.filter((el, idx, arr) => el.table && arr.map((item) => item.table).indexOf(el.table) === idx);
|
|
84
|
-
|
|
85
|
-
const q = unique.map((el) => {
|
|
86
|
-
const where = id
|
|
87
|
-
? `${el.pk}::text='${id.replace(/'/g, "''")}'`
|
|
88
|
-
: `case
|
|
89
|
-
when ST_GeometryType(${el.geomColumn}) in ('ST_Polygon','ST_MultiPolygon')
|
|
90
|
-
then st_intersects(${el.geomColumn},st_buffer('${point.replace(/'/g, "''")}',${el.step}))
|
|
91
|
-
|
|
92
|
-
when ST_GeometryType(${el.geomColumn}) in ('ST_Line','ST_MultiLineString', 'ST_MultiPoint', 'ST_Point')
|
|
93
|
-
then st_distance(${el.geomColumn},'${point.replace(/'/g, "''")}') < ${el.step}
|
|
94
|
-
else false
|
|
95
|
-
end`;
|
|
96
|
-
return `select ${el.pk}::text as pk, '${el.layer}' as layer,
|
|
97
|
-
row_to_json(t) as data,
|
|
98
|
-
${id ? 'null' : `st_distance(${el.geomColumn},'${point.replace(/'/g, "''")}')`} as distance,
|
|
99
|
-
st_asgeojson(${el.geomColumn})::json as geom from (${el.optimizedSQL}) t
|
|
100
|
-
where ${where}`;
|
|
101
|
-
}).join(' union all ').concat(' order by distance');
|
|
102
|
-
|
|
103
|
-
if (sql === '1') return q;
|
|
104
|
-
|
|
105
|
-
const { rows: objects = [] } = await pg.query(q);
|
|
106
|
-
|
|
107
|
-
if (!objects.length) {
|
|
108
|
-
return reply.status(200).send(`object not found: ${id}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const layerData = layers.find((el) => (el.id || el.name) === objects[0].layer) || {};
|
|
112
|
-
const rows = objects.slice(0, 1).map(el => ({ ...el.data, data: undefined }));
|
|
113
|
-
|
|
114
|
-
const { cls, htmls } = layerData;
|
|
115
|
-
await metaFormat({ rows, cls, htmls, sufix: false }, pg);
|
|
116
|
-
|
|
117
|
-
const resp = {
|
|
118
|
-
meta: {
|
|
119
|
-
...layerMetaColumns.reduce((acc, curr) => ({ ...acc, [curr]: layerData[curr] }), {}),
|
|
120
|
-
distance: objects[0].distance,
|
|
121
|
-
},
|
|
122
|
-
data: {
|
|
123
|
-
id: rows[0][layerData.pk],
|
|
124
|
-
...rows[0],
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
return reply.status(200).send(resp);
|
|
1
|
+
import { getMeta, getFilterSQL, getTemplate, metaFormat, pgClients, yml2json } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
const layerMetaColumns = ['id', 'name', 'label', 'source', 'table', 'pk', 'geomColumn', 'srid', 'cls', 'htmls'];
|
|
4
|
+
|
|
5
|
+
export default async function mapFeaturesPoint({ pg = pgClients.client, params = {}, query = {} }, reply) {
|
|
6
|
+
const { slug, id } = params;
|
|
7
|
+
const { x, y, sql } = query;
|
|
8
|
+
|
|
9
|
+
if (!slug) {
|
|
10
|
+
return reply.status(400).send('not enough params: slug');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!(x && y) && !id) {
|
|
14
|
+
return reply.status(400).send('not enough params: xy');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const loadTemplate = await getTemplate('map', slug);
|
|
18
|
+
|
|
19
|
+
if (!loadTemplate) {
|
|
20
|
+
return reply.status(404).send('map not found');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const index = loadTemplate?.find?.(el => el[0].split('.').shift() === 'index')?.[1];
|
|
24
|
+
|
|
25
|
+
const layers1 = !index
|
|
26
|
+
? loadTemplate?.layers
|
|
27
|
+
: loadTemplate?.filter?.(el => el[0].split('.').shift() !== 'index')?.map(el => ({ ...el[1], id: el[0].replace('.yml', '').replace('.json', '') }));
|
|
28
|
+
|
|
29
|
+
const serviceLayers = await Promise.all(layers1.filter(el => typeof el === 'string').map(async (layer) => {
|
|
30
|
+
const layerData = await getTemplate('layer', layer);
|
|
31
|
+
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]);
|
|
32
|
+
serviceData.style = yml2json(serviceData.style);
|
|
33
|
+
return { ...serviceData, id: layer, visible: true };
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const layers = layers1.filter(el => el && typeof el === 'object').concat(serviceLayers);
|
|
37
|
+
|
|
38
|
+
if (!layers?.length) {
|
|
39
|
+
return reply.status(404).send('map layers not found');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!layers.filter(el => el.source_path).length) {
|
|
43
|
+
return reply.status(404).send('map layers sources not provided');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const point = `srid=4326;point(${x} ${y})`; // 30, 50
|
|
47
|
+
|
|
48
|
+
const { srids } = await pg.queryCache?.('select json_agg(srid) as srids from spatial_ref_sys').then(el => el.rows?.[0] || {}) || {};
|
|
49
|
+
|
|
50
|
+
await Promise.all(layers.map(async (layer, idx) => {
|
|
51
|
+
const { source_path: source, srid = 4326, id: layerId, name } = layer;
|
|
52
|
+
|
|
53
|
+
const loadTable = await getTemplate('table', source);
|
|
54
|
+
const meta = await getMeta({ pg, table: loadTable?.table || source });
|
|
55
|
+
const { geom = 'geom' } = meta || {};
|
|
56
|
+
const { table = source, columns = meta?.columns } = loadTable || {};
|
|
57
|
+
|
|
58
|
+
const cls = columns
|
|
59
|
+
?.filter(el => el.name && el.data)
|
|
60
|
+
?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
61
|
+
const htmls = columns
|
|
62
|
+
?.filter(el => el.name && el.html)
|
|
63
|
+
?.reduce?.((acc, curr) => ({ ...acc, [curr.name]: curr.html }), {});
|
|
64
|
+
|
|
65
|
+
const pk = pg.pk?.[table] || loadTable?.key;
|
|
66
|
+
|
|
67
|
+
const { optimizedSQL } = await getFilterSQL({ pg, table: source, query: layer?.query });
|
|
68
|
+
|
|
69
|
+
Object.assign(layer, {
|
|
70
|
+
layer: (layerId || name || idx.toString())?.replace?.(/'/g, "''"),
|
|
71
|
+
table,
|
|
72
|
+
pk,
|
|
73
|
+
cls,
|
|
74
|
+
htmls,
|
|
75
|
+
geomColumn: geom,
|
|
76
|
+
optimizedSQL,
|
|
77
|
+
srid,
|
|
78
|
+
step: srids?.includes?.(srid - 0) && srid !== 4326 ? 10 : 0.0002,
|
|
79
|
+
});
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
const unique = layers
|
|
83
|
+
.filter((el, idx, arr) => el.table && arr.map((item) => item.table).indexOf(el.table) === idx);
|
|
84
|
+
|
|
85
|
+
const q = unique.map((el) => {
|
|
86
|
+
const where = id
|
|
87
|
+
? `${el.pk}::text='${id.replace(/'/g, "''")}'`
|
|
88
|
+
: `case
|
|
89
|
+
when ST_GeometryType(${el.geomColumn}) in ('ST_Polygon','ST_MultiPolygon')
|
|
90
|
+
then st_intersects(${el.geomColumn},st_buffer('${point.replace(/'/g, "''")}',${el.step}))
|
|
91
|
+
|
|
92
|
+
when ST_GeometryType(${el.geomColumn}) in ('ST_Line','ST_MultiLineString', 'ST_MultiPoint', 'ST_Point')
|
|
93
|
+
then st_distance(${el.geomColumn},'${point.replace(/'/g, "''")}') < ${el.step}
|
|
94
|
+
else false
|
|
95
|
+
end`;
|
|
96
|
+
return `select ${el.pk}::text as pk, '${el.layer}' as layer,
|
|
97
|
+
row_to_json(t) as data,
|
|
98
|
+
${id ? 'null' : `st_distance(${el.geomColumn},'${point.replace(/'/g, "''")}')`} as distance,
|
|
99
|
+
st_asgeojson(${el.geomColumn})::json as geom from (${el.optimizedSQL}) t
|
|
100
|
+
where ${where}`;
|
|
101
|
+
}).join(' union all ').concat(' order by distance');
|
|
102
|
+
|
|
103
|
+
if (sql === '1') return q;
|
|
104
|
+
|
|
105
|
+
const { rows: objects = [] } = await pg.query(q);
|
|
106
|
+
|
|
107
|
+
if (!objects.length) {
|
|
108
|
+
return reply.status(200).send(`object not found: ${id}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const layerData = layers.find((el) => (el.id || el.name) === objects[0].layer) || {};
|
|
112
|
+
const rows = objects.slice(0, 1).map(el => ({ ...el.data, data: undefined }));
|
|
113
|
+
|
|
114
|
+
const { cls, htmls } = layerData;
|
|
115
|
+
await metaFormat({ rows, cls, htmls, sufix: false }, pg);
|
|
116
|
+
|
|
117
|
+
const resp = {
|
|
118
|
+
meta: {
|
|
119
|
+
...layerMetaColumns.reduce((acc, curr) => ({ ...acc, [curr]: layerData[curr] }), {}),
|
|
120
|
+
distance: objects[0].distance,
|
|
121
|
+
},
|
|
122
|
+
data: {
|
|
123
|
+
id: rows[0][layerData.pk],
|
|
124
|
+
...rows[0],
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return reply.status(200).send(resp);
|
|
129
129
|
}
|