Skip to content

Commit

Permalink
#581 Populate zooms and bbox from cog/info, LayersTool locate
Browse files Browse the repository at this point in the history
  • Loading branch information
tariqksoliman committed Sep 28, 2024
1 parent 336a3e4 commit 1aa0080
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 51 deletions.
1 change: 1 addition & 0 deletions API/Backend/Config/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ let setup = {
process.env.NODE_ENV === "development"
? ""
: process.env.WEBSOCKET_ROOT_PATH || "",
IS_DOCKER: process.env.IS_DOCKER,
});
}
);
Expand Down
1 change: 1 addition & 0 deletions configure/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
mmgisglobal.PORT = "#{PORT}";
mmgisglobal.ENABLE_CONFIG_WEBSOCKETS = "#{ENABLE_CONFIG_WEBSOCKETS}";
mmgisglobal.ENABLE_CONFIG_OVERRIDE = "#{ENABLE_CONFIG_OVERRIDE}";
mmgisglobal.IS_DOCKER = "#{IS_DOCKER}";
</script>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
Expand Down
120 changes: 80 additions & 40 deletions configure/src/core/Maker.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
getToolFromConfiguration,
updateToolInConfiguration,
getLayerByUUID,
isUrlAbsolute,
} from "./utils";

import Map from "../components/Map/Map";
Expand Down Expand Up @@ -266,12 +267,13 @@ const getComponent = (
variant="outlined"
startIcon={<PrecisionManufacturingIcon />}
onClick={() => {
if (com.action === "tile-populate-from-xml") {
tilePopulateFromXML(
if (com.action === "tile-populate-from-x") {
tilePopulateFromX(
layer.type,
layer.url,
layer.demtileurl,
`Missions/${configuration.msv.mission}/`,
layer.throughTileServer === true,
(minZoom, maxNativeZoom, boundingBox) => {
let conf = updateConfiguration(
"minZoom",
Expand All @@ -296,15 +298,15 @@ const getComponent = (

dispatch(
setSnackBarText({
text: "Successfully populated fields from XML.",
text: "Successfully populated fields from XML or from cog/info.",
severity: "success",
})
);
},
(err) => {
dispatch(
setSnackBarText({
text: "Could not find an XML alongside that URL.",
text: "Could not find an XML or cog/info alongside that URL.",
severity: "error",
})
);
Expand Down Expand Up @@ -1012,11 +1014,12 @@ export default function Maker(props) {
}

// Helper funcs
function tilePopulateFromXML(
function tilePopulateFromX(
layerType,
url,
demTileUrl,
missionPath,
throughTileServer,
cb,
errorCallback
) {
Expand All @@ -1025,43 +1028,80 @@ function tilePopulateFromXML(
// input mission path
// sets, minZoom, maxNativeZoom and boundingBox

let xmlPath = false;
if (layerType === "tile") xmlPath = url;
else if (layerType === "data") xmlPath = demTileUrl;
if (throughTileServer) {
if (layerType === "tile") {
let fullUrl = url;
if (!isUrlAbsolute(url)) {
fullUrl = missionPath.replace("config.json", "") + fullUrl;

if (xmlPath == false) {
///////////////////////////////////////////////////////////////////////////////
return;
}
if (window.mmgisglobal.IS_DOCKER !== "true") {
fullUrl = `../../${fullUrl}`;
}
}

xmlPath = xmlPath.replace("{z}/{x}/{y}.png", "tilemapresource.xml");
xmlPath = missionPath.replace("config.json", "") + xmlPath;
fetch(xmlPath)
.then((response) => response.text())
.then((str) => new window.DOMParser().parseFromString(str, "text/xml"))
.then((xml) => {
try {
const tLen = xml.getElementsByTagName("TileSet").length;
const minZoom =
xml.getElementsByTagName("TileSet")[0].attributes["order"].value;
const maxNativeZoom =
xml.getElementsByTagName("TileSet")[tLen - 1].attributes["order"]
.value;
const boundingBox =
xml.getElementsByTagName("BoundingBox")[0].attributes["minx"].value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["miny"].value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["maxx"].value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["maxy"].value;
fullUrl = `${window.location.origin}/titiler/cog/info?url=${fullUrl}`;

fetch(fullUrl)
.then((response) => response.json())
.then((json) => {
try {
const minZoom = json.minzoom;
const maxNativeZoom = json.maxzoom;

let boundingBox = ``;
if (json.bounds != null)
boundingBox = `${json.bounds[0]},${json.bounds[1]},${json.bounds[2]},${json.bounds[3]}`;
cb(minZoom, maxNativeZoom, boundingBox);
} catch (err) {
errorCallback(err);
}
})
.catch((err) => {
errorCallback(err);
});
}
} else {
let xmlPath = false;
if (layerType === "tile") xmlPath = url;
else if (layerType === "data") xmlPath = demTileUrl;

cb(minZoom, maxNativeZoom, boundingBox);
} catch (err) {
if (xmlPath == false) {
///////////////////////////////////////////////////////////////////////////////
return;
}

xmlPath = xmlPath.replace("{z}/{x}/{y}.png", "tilemapresource.xml");
xmlPath = missionPath.replace("config.json", "") + xmlPath;
fetch(xmlPath)
.then((response) => response.text())
.then((str) => new window.DOMParser().parseFromString(str, "text/xml"))
.then((xml) => {
try {
const tLen = xml.getElementsByTagName("TileSet").length;
const minZoom =
xml.getElementsByTagName("TileSet")[0].attributes["order"].value;
const maxNativeZoom =
xml.getElementsByTagName("TileSet")[tLen - 1].attributes["order"]
.value;
const boundingBox =
xml.getElementsByTagName("BoundingBox")[0].attributes["minx"]
.value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["miny"]
.value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["maxx"]
.value +
"," +
xml.getElementsByTagName("BoundingBox")[0].attributes["maxy"].value;

cb(minZoom, maxNativeZoom, boundingBox);
} catch (err) {
errorCallback(err);
}
})
.catch((err) => {
errorCallback(err);
}
})
.catch((err) => {
errorCallback(err);
});
});
}
}
6 changes: 6 additions & 0 deletions configure/src/core/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { saveAs } from "file-saver";
export const isNumeric = (value) => {
return /^\d+$/.test(value);
};

export const isUrlAbsolute = (url) => {
const r = new RegExp("^(?:[a-z]+:)?//", "i");
return r.test(url);
};

/**
* Traverses an object with an array of keys
* @param {*} obj
Expand Down
8 changes: 4 additions & 4 deletions configure/src/metaconfigs/layer-data-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@
"name": "Actions",
"components": [
{
"name": "Populate Fields From tilemapresource.xml",
"description": "If the above URL is relative to the Missions/{mission} directory and the tileset contains a tilemapresource.xml within it, queries that xml and auto-fills the 'Minimum Zoom', 'Maximum Native Zoom' and 'Bounding Box' fields above.",
"name": "Populate Fields From tilemapresource.xml or from cog/info",
"description": "If the above URL is relative to the Missions/{mission} directory and the tileset contains a tilemapresource.xml within it, queries that xml and auto-fills the 'Minimum Zoom', 'Maximum Native Zoom' and 'Bounding Box' fields above. If it is a COG and TiTiler is true, the COG's data will be queried instead.",
"type": "button",
"action": "tile-populate-from-xml",
"width": 4
"action": "tile-populate-from-x",
"width": 6
}
]
}
Expand Down
8 changes: 4 additions & 4 deletions configure/src/metaconfigs/layer-tile-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@
"name": "Actions",
"components": [
{
"name": "Populate Fields From tilemapresource.xml",
"description": "If the above URL is relative to the Missions/{mission} directory and the tileset contains a tilemapresource.xml within it, queries that xml and auto-fills the 'Minimum Zoom', 'Maximum Native Zoom' and 'Bounding Box' fields above.",
"name": "Populate Fields From tilemapresource.xml or from cog/info",
"description": "If the above URL is relative to the Missions/{mission} directory and the tileset contains a tilemapresource.xml within it, queries that xml and auto-fills the 'Minimum Zoom', 'Maximum Native Zoom' and 'Bounding Box' fields above. If it is a COG and TiTiler is true, the COG's data will be queried instead.",
"type": "button",
"action": "tile-populate-from-xml",
"width": 4
"action": "tile-populate-from-x",
"width": 6
}
]
}
Expand Down
8 changes: 5 additions & 3 deletions src/essence/Tools/Layers/LayersTool.css
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@
font-size: 12px;
}
#layersTool .settings .layerSettingsTitle > div:last-child {

}
#layersTool .settings ul > li {
line-height: 30px;
Expand Down Expand Up @@ -297,6 +296,7 @@
#layersTool .reset,
#layersTool .layerDownload,
#layersTool .gears,
#layersTool .locate,
#layersTool .LayersToolInfo,
#layersTool .time {
width: 30px;
Expand All @@ -311,12 +311,14 @@
#layersTool .reload,
#layersTool .layerDownload,
#layersTool .gears,
#layersTool .locate,
#layersTool .LayersToolInfo {
color: transparent;
}
#layersTool .reload:hover,
#layersTool .layerDownload:hover,
#layersTool .gears:hover,
#layersTool .locate:hover,
#layersTool .LayersToolInfo:hover {
background: var(--color-k);
}
Expand All @@ -336,6 +338,7 @@
#layersTool li.gears_on .gears,
#layersTool li:hover .reload,
#layersTool li:hover .gears,
#layersTool li:hover .locate,
#layersTool li:hover .LayersToolInfo {
color: #fff;
}
Expand Down Expand Up @@ -620,7 +623,6 @@
}
}


.layersToolExport {
cursor: default;
height: unset !important;
Expand Down Expand Up @@ -674,4 +676,4 @@
}
.layersToolExportGo:hover {
background-color: var(--color-a1-5);
}
}
66 changes: 66 additions & 0 deletions src/essence/Tools/Layers/LayersTool.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,9 @@ function interfaceWithMMGIS(fromInit) {
'<div title="Settings" class="gears" id="layersettings' + F_.getSafeName(node[i].name) + '" stype="' + node[i].type + '" layername="' + node[i].name + '">',
'<i class="mdi mdi-tune mdi-18px" name="layersettings"></i>',
'</div>',
'<div title="Locate" class="locate" id="layerlocate' + F_.getSafeName(node[i].name) + '" stype="' + node[i].type + '" layername="' + node[i].name + '">',
'<i class="mdi mdi-crosshairs-gps mdi-18px" name="layerlocate"></i>',
'</div>',
'<div title="Information" class="LayersToolInfo" id="layerinfo' + F_.getSafeName(node[i].name) + '" stype="' + node[i].type + '" layername="' + node[i].name + '">',
'<i class="mdi mdi-information-outline mdi-18px" name="layerinfo"></i>',
'</div>',
Expand Down Expand Up @@ -826,6 +829,69 @@ function interfaceWithMMGIS(fromInit) {
}
}
})

// Locates/zooms to fill extent of layer
$('#layersTool .locate').on('click', function (e) {
e.stopPropagation()
const layerName = $(this).attr('layername')
const data = L_.layers.data[layerName]
const layer = L_.layers.layer[layerName]

if (!data || !layer) {
CursorInfo.update(
'Unable to locate layer.',
4000,
true,
{ x: 385, y: 6 },
'#e9ff26',
'black'
)
return
}

if (L_.layers.on[layerName] !== true) {
CursorInfo.update(
'Please turn the layer on before locating.',
4000,
true,
{ x: 385, y: 6 },
'#e9ff26',
'black'
)
return
}

try {
if (typeof layer.getBounds === 'function') {
Map_.map.fitBounds(layer.getBounds())
} else if (data.boundingBox) {
Map_.map.fitBounds([
[data.boundingBox[1], data.boundingBox[0]],
[data.boundingBox[3], data.boundingBox[2]],
])
} else {
CursorInfo.update(
'Unable to locate layer.',
4000,
true,
{ x: 385, y: 6 },
'#e9ff26',
'black'
)
return
}
} catch (err) {
CursorInfo.update(
'Unable to locate layer.',
4000,
true,
{ x: 385, y: 6 },
'#e9ff26',
'black'
)
return
}
})
//Enables the time dialogue box
$('.LayersToolInfo').on('click', function (e) {
e.stopPropagation()
Expand Down

0 comments on commit 1aa0080

Please sign in to comment.