@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.
@@ -1,15 +1,23 @@
1
- import { config, pgClients, yml2json } from '@opengis/fastify-table/utils.js';
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
- pg = pgClients.client, query = {}, user = {},
6
+ pg = pgClients.client, query = {}, user = {},
5
7
  }, reply) {
6
- const { sql } = query;
7
-
8
- if (!pg.pk?.['gis.services']) {
9
- return reply.status(404).send('services table not found');
10
- }
11
-
12
- const q = `
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
- if (user.uid && sql) return q;
30
+ if (user.uid && sql) return q;
31
+
32
+ const rows = await pg.query(q).then(el => el.rows || []);
23
33
 
24
- const rows = await pg.query(q).then(el => el.rows || []);
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
- const totals = pg.queryCache ? await pg.queryCache(`select json_object_agg(oid::regclass, reltuples) from pg_class`)
27
- .then(el => el.rows?.[0]?.json_object_agg || {}) : {};
28
- rows.filter(row => row.source_path).forEach(row => Object.assign(row, { count: totals[row.source_path] || 0 }));
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
- const groupIds = rows.map(el => el.group_id).filter(Boolean);
31
- 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 || {}) : {};
32
- rows.filter(el => el.group_id).forEach(row => Object.assign(row, { group_name: groupNames[row.group_id] }));
42
+ if (!rows.length) {
43
+ return reply.status(200).send([]);
44
+ }
33
45
 
34
- if (!rows.length) {
35
- return reply.status(200).send([]);
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
- // parse service style
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
- return reply.status(200).send(rows);
50
- }
59
+ return reply.status(200).send(rows.concat(files));
60
+ }
@@ -1,125 +1,85 @@
1
- import { pgClients, getTemplate, handlebars, metaFormat } from "@opengis/fastify-table/utils.js";
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
- const { pg = pgClients.client, query = {} } = req;
5
- const { layer, id, map } = query;
6
- const time = Date.now();
7
-
8
- if (!layer || !id) return reply.status(404).send('not enough params: layer,id,map is required');
9
-
10
- let service = null;
11
-
12
- if (map) {
13
- const {
14
- rows: [mapLayer],
15
- } = await pg.query(
16
- `select s.*
17
- from gis.maps_layers ml
18
- join gis.services s on s.service_id = ml.service_id
19
- join gis.maps m on m.map_id = ml.map_id
20
- where m.map_key = $1 and s.service_key = $2`,
21
- [map, layer]
22
- );
23
-
24
- if (mapLayer) {
25
- service = mapLayer;
26
- }
27
- } else {
28
- const {
29
- rows: [s],
30
- } = await pg.query(`SELECT * FROM gis.services WHERE service_id = $1`, [layer]);
31
-
32
- if (s) {
33
- service = s;
34
- }
35
- }
36
-
37
- let source_path, tpl, cardInterface, card, template;
38
- if (service) {
39
- ({ source_path, interface: cardInterface, card, template } = service);
40
- } else {
41
- // git
42
- tpl = await getTemplate('map', map);
43
- const matchedLayer = tpl?.layers?.find(l => l.id === layer || l.service === layer);
44
- if (!matchedLayer || !matchedLayer.source_path || !matchedLayer.card) {
45
- return reply.status(404).send('template not found');
46
- };
47
- source_path = matchedLayer.source_path;
48
- card = matchedLayer.card;
49
- template = matchedLayer.template;
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
- if (col.format === 'date' && fullRow[col.name]) {
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
- const htmlTemplate = pg?.pk?.['admin.template']
103
- ? await pg.query('select body from admin.templates where name=$1 limit 1', [template || id]).then(el => el.rows?.[0]?.body)
104
- : null;
105
-
106
- const html1 = await handlebars.compile(htmlTemplate || 'template not found')(fullRow);
107
-
108
- const html = template
109
- ? html1
110
- : `<dl class="divide-y divide-gray-100 py-[5px]">${result.join('')}</dl>`;
111
-
112
- const res = {
113
- time: Date.now() - time,
114
- id,
115
- rows: fullRow,
116
- columns,
117
- template,
118
- html
119
- };
120
- if (service) {
121
- res.cardInterface = cardInterface;
122
- }
123
-
124
- return res;
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 { ...rows[0], ...obj, layers };
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
- 'Content-Type': 'application/x-protobuf',
3
- 'Cache-Control': 'no-cache',
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 { getColumnCLS, getTemplate, getMeta, getFilterSQL } from '@opengis/fastify-table/utils.js';
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({ params = {}, query, pg, user }, reply) {
13
- const { y, z } = params;
14
- const x = params.x.split('.')[0] - 0;
15
-
16
- // layer
17
- const [map, layer] = params.layer.includes(':') ? params.layer.split(':') : [null, params.layer];
18
- const data = await getTemplate('layer', layer);
19
- // service
20
- const data1 = 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]);
21
- if (!data && !data1) return { status: 404, message: 'not found' }
22
-
23
- // style
24
- const mapData = map ? await getTemplate('map', map) : {};
25
- const mapStyle = mapData?.widgets?.find?.(el => el.type === 'attribute')?.config?.layer?.style;
26
-
27
- const geom = data?.geometry_column
28
- || data1?.geometry_column
29
- || 'geom';
30
- const table = data?.source_path
31
- || data?.table_name
32
- || data1?.source_path;
33
- const style = mapStyle
34
- || data?.style
35
- || (data1?.style ? yaml.load(data1?.style) : null);
36
- const filterList = data?.filters
37
- || data?.filter_list
38
- || data1?.filters;
39
- const layerQuery = data?.query || data1?.query;
40
-
41
- // bbox
42
- const bbox = mercator.bbox(+y, +x, +z, false/* , '900913' */);
43
- const bbox2d = `'BOX(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d`;
44
-
45
- const filterData = query.filter ? await getFilterSQL({
46
- filter: query.filter, table, filterList,
47
- }) : {};
48
-
49
- // meta
50
- const metaTable = await getMeta({ pg, table });
51
- if (metaTable.error) { return metaTable; }
52
- const { pk: pkey, columns } = metaTable;
53
-
54
- // props
55
- const columnsFiltered = columns.filter(el => !['json', 'geometry'].includes(pg.pgType[el.dataTypeID]) && !['uid', 'cdate', 'editor_id', 'editor_date'].includes(el.name));
56
- const props = columnsFiltered.map(el => {
57
- return el.type?.[0] === '_' ? `${el.name}[1] as ${el.name}` : `${el.name}${['int4'].includes(el.type) ? '::text' : ''}`;
58
- });
59
-
60
- const obj = (data1.attributes || []).concat(data1.card || []).concat(data1.popup || []).filter(el => el.data).reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
61
-
62
- const propsWithCls = propsCache[layer] ?? await Promise.all(props.map(async (key, idx) => {
63
- const { name, type, sql } = getColumnCLS(table, key) || {};
64
- if (name && type === 'cls') {
65
- return `(select name from admin.cls where parent='${name}' and code::text="${key}"::text limit 1) as "${key}_text","${key}"::text`;
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
- const koef = {
90
- 10: 0.1, 11: 0.05, 12: 0.005, 13: 0.001, 14: 0.001, 15: 0.0005,
91
- }[z] || 0.0005;
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
- const { type } = query;
94
- const types = { point: 'ST_Point' /* ,ST_MultiPoint */, polygon: 'ST_Polygon,ST_MultiPolygon' };
95
- const sql = ((query.clusterZoom - z) > 2
96
- ? `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
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`: null
103
- ) || ((query.clusterZoom - z) > 0 ?
104
- `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
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
- : `SELECT ST_AsMVT(q, '${layer}', 4096, 'geom','row') as tile
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
- if (query.sql === '1') { return sql; }
142
- const tile = await pg.query(sql);
143
- const buffer = Buffer.concat(tile.rows.map((el) => Buffer.from(el.tile)));
144
- return reply.headers(headers).send(buffer);
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,6 +0,0 @@
1
- label: Адреси
2
- source_path: data_address.address
3
- style:
4
- color: "#555"
5
- weight: 1.5
6
- visible: false
@@ -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,9 +0,0 @@
1
- {
2
- "label": "Адреси",
3
- "source_path": "data_address.address",
4
- "style": {
5
- "color": "#555",
6
- "weight": 1.5
7
- },
8
- "visible": false
9
- }
@@ -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
- }