Commit 73533621 authored by Anne Blankert's avatar Anne Blankert

mvt include_nulls option, basic map legend

parent 3f99b45c
...@@ -6,8 +6,38 @@ const merc = new sm({ ...@@ -6,8 +6,38 @@ const merc = new sm({
size: 256 size: 256
}) })
function queryColumnsNotNull(queryColumns) { function toBoolean(value) {
if (queryColumns) { if (!value) {
return false;
}
if (typeof value === 'string'){
if (value.trim() === '') {
return false;
} else if (Number(value) === NaN) {
switch (value.toLowerCase().trim()) {
case 'no':
case 'false':
case 'n':
case 'f':
return false;
default:
return true;
}
} else {
return Number(value) !== 0;
}
}
if (Number(value)!== NaN) {
return Number(value) !== 0;
}
return true;
}
function queryColumnsNotNull(query) {
const queryColumns = query.columns;
const includeNulls = toBoolean(query.include_nulls);
if (!includeNulls && queryColumns) {
return ` and (${queryColumns.split(',').map(column=>`${column} is not null`).join(' or ')})` return ` and (${queryColumns.split(',').map(column=>`${column} is not null`).join(' or ')})`
} }
return '' return ''
...@@ -36,7 +66,7 @@ const sql = (params, query) => { ...@@ -36,7 +66,7 @@ const sql = (params, query) => {
ST_MakeEnvelope(${bounds.join()}, 3857), ST_MakeEnvelope(${bounds.join()}, 3857),
srid srid
) && ${query.geom_column} ) && ${query.geom_column}
${queryColumnsNotNull(query.columns)} ${queryColumnsNotNull(query)}
-- Optional Filter -- Optional Filter
${query.filter ? `AND ${query.filter}` : ''} ${query.filter ? `AND ${query.filter}` : ''}
) r ) r
...@@ -52,7 +82,7 @@ module.exports = function(app, pool, cache) { ...@@ -52,7 +82,7 @@ module.exports = function(app, pool, cache) {
return; return;
} }
const cacheDir = `${req.params.datasource}/mvt/${req.params.z}/${req.params.x}/${req.params.y}`; const cacheDir = `${req.params.datasource}/mvt/${req.params.z}/${req.params.x}/${req.params.y}`;
const key = ((req.query.geom_column?req.query.geom_column:'geom') + (req.query.columns?','+req.query.columns:'')) const key = ((req.query.geom_column?req.query.geom_column:'geom') + (req.query.columns?','+req.query.columns:'')) + (toBoolean(req.query.include_nulls)?'_includenulls':'')
.replace(/[\W]+/g, '_'); .replace(/[\W]+/g, '_');
const mvt = await cache.getCachedFile(cacheDir, key); const mvt = await cache.getCachedFile(cacheDir, key);
...@@ -114,6 +144,11 @@ module.exports = function(app, pool, cache) { ...@@ -114,6 +144,11 @@ module.exports = function(app, pool, cache) {
* in: query * in: query
* required: false * required: false
* type: string * type: string
* - name: include_nulls
* description: 'optional parameter to include geometries where all attribute columns are null (default: false)'
* in: query
* required: false
* type: string
* responses: * responses:
* 200: * 200:
* description: vector tile * description: vector tile
......
...@@ -4,12 +4,21 @@ ...@@ -4,12 +4,21 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Info</title> <title>PGServer Info</title>
<style> <style>
.medium {width: 300px; height: auto;} .medium {width: 300px; height: auto;}
#mapcontainer {
display: flex;
flex-wrap: wrap;
}
#map {display: inline-block; width: 500px; height: 500px; border: 1 px solid lightblue;} #map {display: inline-block; width: 500px; height: 500px; border: 1 px solid lightblue;}
#info {display: inline-block;} #featurecontainer {
display: flex;
flex-direction: column;
justify-content: space-between;
}
#feaureinfo {display: inline-block;}
#attrinfo { #attrinfo {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
...@@ -72,6 +81,16 @@ ...@@ -72,6 +81,16 @@
}) })
} }
function addLegendLine(color, label) {
const legend = document.querySelector('#legend');
const svg = `<svg width="30" height="15">
<rect width="30" height="15" style="fill:${color};fill-opacity:1;stroke-width:1;stroke:#444"></rect>
</svg>`
const legendLine = document.createElement('div');
legendLine.innerHTML = `<div><span>${svg}</span><span>${label}<span></div>`
legend.appendChild(legendLine);
}
function initMap() function initMap()
{ {
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
...@@ -103,11 +122,7 @@ ...@@ -103,11 +122,7 @@
"type": "raster", "type": "raster",
"source": "osmgray" "source": "osmgray"
} }
], ]
"filter": [
"has",
`${attrName}`
]
} }
} }
const bboxll = urlParams.get('bboxll'); const bboxll = urlParams.get('bboxll');
...@@ -157,19 +172,20 @@ ...@@ -157,19 +172,20 @@
"type": layerType, "type": layerType,
"source": { "source": {
"type": "vector", "type": "vector",
"tiles": [`${baseUrl}/${fullTableName}/mvt/{z}/{x}/{y}?geom_column=${geomColumn}&columns=${attrName}`], "tiles": [`${baseUrl}/${fullTableName}/mvt/{z}/{x}/{y}?geom_column=${geomColumn}&columns=${attrName}&include_nulls=0`],
}, },
"source-layer": fullTableName, "source-layer": fullTableName,
"paint": paint, "paint": paint,
"filter": ['has', attrName] //"filter": ['has', attrName]
} }
map.addLayer(layer); map.addLayer(layer);
addLegendLine('red', fullTableName);
document.querySelector("#layerjson").innerHTML = `<pre>${JSON.stringify(layer, null, 2)}</pre>`; document.querySelector("#layerjson").innerHTML = `<pre>${JSON.stringify(layer, null, 2)}</pre>`;
} }
}) })
map.on('mousemove', function (e) { map.on('mousemove', function (e) {
var features = map.queryRenderedFeatures(e.point).map(function(feature){ return {layer: {id: feature.layer.id, type: feature.layer.type}, properties:(feature.properties)};}); var features = map.queryRenderedFeatures(e.point).map(function(feature){ return {layer: {id: feature.layer.id, type: feature.layer.type}, properties:(feature.properties)};});
document.getElementById('info').innerHTML = JSON.stringify(features.map(feature=>feature.properties), null, 2); document.querySelector('#featureinfo').innerHTML = JSON.stringify(features.map(feature=>feature.properties), null, 2);
}); });
} }
...@@ -292,8 +308,21 @@ ...@@ -292,8 +308,21 @@
<div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="dot"></div> <div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="dot"></div>
</div> </div>
</div> </div>
<div id="map"></div> <div id="mapcontainer">
<div id="info"></div> <div id="map"></div>
<div id="featurecontainer">
<div id="legendcontainer">
<select id="numclasses" name="numclasses">
<option>1</option>
</select><label for="numclasses">number of classes</label><br>
<button>equal interval</button>
<button>quantile</button><br>
<input type="checkbox" id="hidenulls" name="hidenulls" checked><label for="hidenulls">Hide null values</label>
<div id="legend"></div>
</div>
<div id="featureinfo"></div>
</div>
</div>
<div id="layerjson"></div> <div id="layerjson"></div>
<div id="back"></div> <div id="back"></div>
</body> </body>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="pgserver.css"> <link rel="stylesheet" href="pgserver.css">
<title>Welcome</title> <title>PGServer UI</title>
</head> </head>
<style> <style>
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<h1>PGServer</h1> <h1>PGServer</h1>
Welcome to pgserver<br> Welcome to pgserver<br>
<a href="/info.html">Browse geo-data</a><br> <a href="/info.html">Browse geo-data</a><br>
<a href="/api-docs">Swagger api docs</a><br> <a href="/api-docs">API documentation (swagger)</a><br>
<a href="/upload.html">Upload files</a> <a href="/upload.html">Upload files</a>
</body> </body>
</html> </html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment