Skip to content

Commit

Permalink
#578 Next/Previous Feature (#579)
Browse files Browse the repository at this point in the history
* #578 Next/Previous part 1 - working next previous on index, menu ui that does nothing

* Quick fix

* #578 Some work on dropdown

* #578 Current Extent, Pan to and touchups

* #578 Arrow keys, first/last, bug fixes

* #578 dynamicExtent and time - partial

* #578 Small fixes, geom precision, ui tweaks

* #578 Better dynamicExtent next-preving

* #578 next/prev improvements

* #578 Next/Prev final touchups
  • Loading branch information
tariqksoliman authored Aug 15, 2024
1 parent df16a71 commit 8ce9eb3
Show file tree
Hide file tree
Showing 15 changed files with 1,183 additions and 68 deletions.
104 changes: 87 additions & 17 deletions API/Backend/Geodatasets/routes/geodatasets.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function get(reqtype, req, res, next) {
if (result) {
let table = result.dataValues.table;
if (type == "geojson") {
let q = `SELECT properties, ST_AsGeoJSON(geom) FROM ${table}`;
let q = `SELECT properties, ST_AsGeoJSON(geom), id FROM ${table}`;

if (req.query?.limited) {
q += ` ORDER BY id DESC LIMIT 3`;
Expand Down Expand Up @@ -124,6 +124,8 @@ function get(reqtype, req, res, next) {
let geojson = { type: "FeatureCollection", features: [] };
for (let i = 0; i < results.length; i++) {
let properties = results[i].properties;
properties._ = properties._ || {};
properties._.idx = results[i].id;
let feature = {};
feature.type = "Feature";
feature.properties = properties;
Expand Down Expand Up @@ -365,6 +367,9 @@ router.post("/entries", function (req, res, next) {
* req.body.layer
* req.body.key
* req.body.value
* req.body.id (specific feature id instead of key:value)
* req.body.orderBy
* req.body.offset (i.e. if -1, then return feature previous to key:val) (can also be 'first' or 'last')
*/
router.post("/search", function (req, res, next) {
//First Find the table name
Expand All @@ -373,34 +378,99 @@ router.post("/search", function (req, res, next) {
if (result) {
let table = result.dataValues.table;

let offset = req.body.offset;
const origOffset = offset;
if (offset === "first") offset = -1;
else if (offset === "last") offset = 1;

let featureId = req.body.id;

if (offset != null && featureId == null) {
res.send({
status: "failure",
message: "If 'offset' is set, 'id' must also be set.",
});
return;
}
offset = parseInt(offset);
featureId = parseInt(featureId);

let orderBy = "id";
if (req.body.orderBy != null)
orderBy = `properties->>'${req.body.orderBy}'`;

let minx = req.body?.minx;
let miny = req.body?.miny;
let maxx = req.body?.maxx;
let maxy = req.body?.maxy;
let where = "";
if (minx != null && miny != null && maxx != null && maxy != null) {
// ST_MakeEnvelope is (xmin, ymin, xmax, ymax, srid)
where = ` WHERE ST_Intersects(ST_MakeEnvelope(${parseFloat(
minx
)}, ${parseFloat(miny)}, ${parseFloat(maxx)}, ${parseFloat(
maxy
)}, 4326), geom)`;
}

let q =
"SELECT properties, ST_AsGeoJSON(geom), id FROM " +
table +
(req.body.last || offset != null
? `${where} ORDER BY id ${offset != null ? "ASC" : "DESC LIMIT 1"}`
: " WHERE properties ->> :key = :value");

sequelize
.query(
"SELECT properties, ST_AsGeoJSON(geom) FROM " +
table +
(req.body.last
? " ORDER BY id DESC LIMIT 1;"
: " WHERE properties ->> :key = :value;"),
{
replacements: {
key: req.body.key,
value:
typeof req.body.value === "string"
? req.body.value.replace(/[`;'"]/gi, "")
: null,
},
}
)
.query(q + ";", {
replacements: {
key: req.body.key,
value:
typeof req.body.value === "string"
? req.body.value.replace(/[`;'"]/gi, "")
: null,
},
})
.then(([results]) => {
let r = [];
for (let i = 0; i < results.length; i++) {
let properties = results[i].properties;
properties._ = properties._ || {};
properties._.idx = results[i].id;
let feature = {};
feature.type = "Feature";
feature.properties = properties;
feature.geometry = JSON.parse(results[i].st_asgeojson);
r.push(feature);
}

if (offset != null) {
if (orderBy != "id") {
r.sort((a, b) => {
let sign = 1;
if (offset > 0) sign = -1;
const af = Utils.getIn(a, `properties.${orderBy}`, 0);
const bf = Utils.getIn(b, `properties.${orderBy}`, 1);
if (typeof af === "string" || typeof bf === "string") {
return af.localeCompare(bf) * sign;
} else return (af - bf) * sign;
});
}

const rLen = r.length;
if (origOffset === "first" || origOffset === "last") {
r = [r[rLen - 1]];
} else {
for (let i = 0; i < rLen; i++) {
if (r[i].properties._.idx === featureId) {
r = [
r[Math.min(Math.max(0, i + Math.abs(offset)), rLen - 1)],
]; //abs because we already sort differently by it
break;
}
}
}
}

res.send({
status: "success",
body: r,
Expand Down
2 changes: 1 addition & 1 deletion configure/src/metaconfigs/layer-query-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@
"defaultChecked": false
},
{
"field": "variables.dynamicExtentThreshold",
"field": "variables.dynamicExtentMoveThreshold",
"name": "Threshold",
"description": "If dynamicExtent is true, only requery if the map was panned past the stated threshold. Unit is in meters. If a zoom-dependent threshold is desired, set this value to a string ending in '/z'. This will then internally use 'dynamicExtentMoveThreshold / Math.pow(2, zoom)' as the threshold value.",
"type": "text",
Expand Down
2 changes: 1 addition & 1 deletion configure/src/metaconfigs/layer-vector-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@
"defaultChecked": false
},
{
"field": "variables.dynamicExtentThreshold",
"field": "variables.dynamicExtentMoveThreshold",
"name": "Threshold",
"description": "If dynamicExtent is true, only requery if the map was panned past the stated threshold. Unit is in meters. If a zoom-dependent threshold is desired, set this value to a string ending in '/z'. This will then internally use 'dynamicExtentMoveThreshold / Math.pow(2, zoom)' as the threshold value.",
"type": "text",
Expand Down
2 changes: 1 addition & 1 deletion configure/src/metaconfigs/layer-vectortile-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@
"defaultChecked": false
},
{
"field": "variables.dynamicExtentThreshold",
"field": "variables.dynamicExtentMoveThreshold",
"name": "Threshold",
"description": "If dynamicExtent is true, only requery if the map was panned past the stated threshold. Unit is in meters. If a zoom-dependent threshold is desired, set this value to a string ending in '/z'. This will then internally use 'dynamicExtentMoveThreshold / Math.pow(2, zoom)' as the threshold value.",
"type": "text",
Expand Down
131 changes: 131 additions & 0 deletions src/essence/Ancillary/Description.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#mainDescNavBar {
display: flex;
background: var(--color-a1);
margin-right: 8px;
}
#mainDescNavBarMenu {
width: 22px;
height: 30px;
text-align: center;
line-height: 30px;
background: var(--color-a);
color: var(--color-a6);
cursor: pointer;
transition: background 0.2s ease-in-out;
}
#mainDescNavBarMenu:hover {
background: rgba(255, 255, 255, 0.1);
}
#mainDescNavBarPrevious {
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border-right: 1px solid var(--color-a);
cursor: pointer;
transition: background 0.2s ease-in-out;
}
#mainDescNavBarPrevious:hover {
background: rgba(255, 255, 255, 0.1);
}
#mainDescNavBarNext {
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
cursor: pointer;
transition: background 0.2s ease-in-out;
}
#mainDescNavBarNext:hover {
background: rgba(255, 255, 255, 0.1);
}

#mainDescNavPopover {
display: none;
background: var(--color-a);
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
width: 240px;
border-top: 1px solid var(--color-a1);
transition: left 0.2s ease-out;
}
#mainDescNavPopoverTitle {
background: var(--color-a2);
text-align: center;
padding: 4px 0px;
font-size: 14px;
letter-spacing: 1px;
border-bottom: 1px solid var(--color-a);
}
#mainDescNavPopoverField {
display: flex;
justify-content: space-between;
height: 30px;
line-height: 30px;
font-size: 14px;
border-bottom: 1px solid var(--color-a1);
}
#mainDescNavPopoverFieldField {
width: 100%;
}
#mainDescNavPopoverFieldInfo {
display: flex;
justify-content: space-between;
padding: 8px 6px 6px 16px;
border-bottom: 1px solid var(--color-a1);
}
#mainDescNavPopoverFieldInfo > div:first-child {
color: var(--color-a6);
margin-right: 8px;
font-size: 12px;
line-height: 18px;
}
#mainDescNavPopoverFieldInfo > div:last-child {
color: var(--color-h);
font-size: 14px;
font-weight: bold;
font-family: monospace;
word-break: break-all;
}
#mainDescNavPopoverExtent,
#mainDescNavPopoverTimeExtent,
#mainDescNavPopoverPanTo {
display: flex;
justify-content: space-between;
height: 30px;
line-height: 30px;
font-size: 14px;
padding-left: 8px;
border-bottom: 1px solid var(--color-a1);
}
#mainDescNavPopoverBottom {
display: flex;
justify-content: center;
height: 30px;
line-height: 30px;
}
#mainDescNavPopoverBottom > div {
width: 30px;
height: 30px;
cursor: pointer;
text-align: center;
transition: background 0.2s ease-in-out;
}
#mainDescNavPopoverBottom > div:hover {
background: var(--color-a1);
}

#mainDescNavPopoverFieldField .dropy__title {
height: 30px;
border: none;
background: var(--color-a1);
line-height: 14px;
font-size: 14px;
}
#mainDescNavPopoverFieldField .dropy__title > i {
line-height: 15px;
}
#mainDescNavPopoverFieldField .dropy__content a {
height: 30px;
line-height: 30px;
padding: 2px 8px;
}
Loading

0 comments on commit 8ce9eb3

Please sign in to comment.