-
-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4502 from mdouchin/lizmap-features-table
New Lizmap web component lizmap-features-table to display a compact list of features
- Loading branch information
Showing
15 changed files
with
2,626 additions
and
85 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/** | ||
* @module modules/FeaturesTable.js | ||
* @name FeaturesTable | ||
* @copyright 2024 3Liz | ||
* @license MPL-2.0 | ||
*/ | ||
import { mainLizmap, mainEventDispatcher } from '../modules/Globals.js'; | ||
import Utils from './Utils.js'; | ||
|
||
/** | ||
* @class | ||
* @name FeaturesTable | ||
*/ | ||
export default class FeaturesTable { | ||
|
||
constructor() { | ||
|
||
} | ||
|
||
/** | ||
* Get the list of features containing the display expression | ||
* | ||
* @param | ||
* @return {Promise} features - Promise with the JSON list of features | ||
*/ | ||
|
||
|
||
/** | ||
* Get the list of features containing the display expression | ||
* | ||
* @param {string} layerId The QGIS layer ID | ||
* @param {string|null} filter An QGIS expression filter | ||
* @param {boolean} withGeometry If we need to get the geometry | ||
* @param {string|null} fields List of field names separated by comma | ||
* | ||
* @returns — A Promise that resolves with the result of parsing the response body text as JSON. | ||
* @throws — {ResponseError} In case of invalid content type (not application/json or application/vnd.geo+json) or Invalid JSON | ||
* @throws — {HttpError} In case of not successful response (status not in the range 200 – 299) | ||
* @throws — {NetworkError} In case of catch exceptions | ||
*/ | ||
getFeatures(layerId, filter = null, withGeometry = false, fields = 'null') { | ||
|
||
// Build URL | ||
const url = `${lizUrls.service.replace('service?','features/displayExpression?')}&`; | ||
|
||
// Build parameters | ||
let formData = new FormData(); | ||
formData.append('layerId', layerId); | ||
formData.append('exp_filter', filter); | ||
formData.append('with_geometry', withGeometry.toString()); | ||
formData.append('fields', fields); | ||
|
||
// Return promise | ||
return Utils.fetchJSON(url, { | ||
method: "POST", | ||
body: formData | ||
}); | ||
} | ||
|
||
|
||
/** | ||
* Display a lizMap message | ||
* | ||
* @param {string} message Message to display | ||
* @param {string} type Type : error or info | ||
* @param {number} duration Number of millisecond the message must be displayed | ||
*/ | ||
addMessage(message, type='info', duration=60000) { | ||
|
||
let previousMessage = document.getElementById('lizmap-features-table-message'); | ||
if (previousMessage) previousMessage.remove(); | ||
mainLizmap.lizmap3.addMessage( | ||
message, type, true, duration | ||
).attr('id', 'lizmap-features-table-message'); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Open a Lizmap Popup | ||
* | ||
* @param {string} layerId QGIS layer ID | ||
* @param {object} feature WFS Feature | ||
* @param {string} uniqueField Field containing unique values (used to set the filter for the WMS request) | ||
* @param {HTMLElement} targetElement Target HTML element to display the popup content for the given feature | ||
* @param {callBack} callBack Callback function | ||
*/ | ||
openPopup(layerId, feature, uniqueField, targetElement, aCallBack) { | ||
|
||
// Get the layer name & configuration | ||
if (!mainLizmap.initialConfig.layers.layerIds.includes(layerId)) { | ||
return null; | ||
} | ||
const layerConfig = mainLizmap.initialConfig.layers.getLayerConfigByLayerId(layerId); | ||
const layerName = layerConfig.name; | ||
|
||
// Layer WMS name | ||
const wmsName = layerConfig?.shortname || layerConfig?.name || layerName; | ||
|
||
// Filter | ||
const filter = `${wmsName}:"${uniqueField}" = '${feature.properties[uniqueField]}'`; | ||
|
||
var crs = 'EPSG:4326'; | ||
if(layerConfig.crs && layerConfig.crs != ''){ | ||
crs = layerConfig.crs; | ||
} | ||
|
||
var wmsOptions = { | ||
'LAYERS': wmsName | ||
,'QUERY_LAYERS': wmsName | ||
,'STYLES': '' | ||
,'SERVICE': 'WMS' | ||
,'VERSION': '1.3.0' | ||
,'CRS': crs | ||
,'REQUEST': 'GetFeatureInfo' | ||
,'EXCEPTIONS': 'application/vnd.ogc.se_inimage' | ||
,'INFO_FORMAT': 'text/html' | ||
,'FEATURE_COUNT': 1 | ||
,'FILTER': filter, | ||
|
||
}; | ||
|
||
// Query the server | ||
$.get(globalThis['lizUrls'].service, wmsOptions, function(data) { | ||
// Display the popup in the target element | ||
if (targetElement) { | ||
targetElement.innerHTML = data; | ||
} | ||
|
||
// Launch callback | ||
aCallBack(layerId, feature, targetElement); | ||
}); | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
<?php | ||
/** | ||
* Get features from QGIS Server with the help of expressions. | ||
* | ||
* @author 3liz | ||
* @copyright 2024 3liz | ||
* | ||
* @see https://3liz.com | ||
* | ||
* @license Mozilla Public License : https://www.mozilla.org/MPL/ | ||
*/ | ||
class featuresCtrl extends jController | ||
{ | ||
/** | ||
* Get all tooltips of a given layer. | ||
* | ||
* @urlparam $REPOSITORY Name of the repository | ||
* @urlparam $PROJECT Name of the project | ||
* @urlparam $LAYERID Layer Id | ||
* | ||
* @return jResponseJson geoJSON content | ||
*/ | ||
public function tooltips() | ||
{ | ||
/** @var jResponseJson $rep */ | ||
$rep = $this->getResponse('json'); | ||
$content = array(); | ||
$rep->data = $content; | ||
|
||
// Get project and repository, and check rights | ||
$project = $this->param('project'); | ||
$repository = $this->param('repository'); | ||
$layerId = trim($this->param('layerId', '')); | ||
$lproj = null; | ||
|
||
try { | ||
$lproj = lizmap::getProject($repository.'~'.$project); | ||
if (!$lproj) { | ||
jMessage::add('The lizmap project '.strtoupper($project).' does not exist !', 'ProjectNotDefined'); | ||
|
||
return $rep; | ||
} | ||
} catch (\Lizmap\Project\UnknownLizmapProjectException $e) { | ||
jLog::logEx($e, 'error'); | ||
jMessage::add('The lizmap project '.strtoupper($project).' does not exist !', 'ProjectNotDefined'); | ||
|
||
return $rep; | ||
} | ||
if (!$lproj->checkAcl()) { | ||
jMessage::add(jLocale::get('view~default.repository.access.denied'), 'AuthorizationRequired'); | ||
|
||
return $rep; | ||
} | ||
|
||
$qgisLayer = $lproj->getLayer($layerId); | ||
|
||
if (!$qgisLayer) { | ||
jMessage::add('The layer Id '.$layerId.' does not exist !', 'error'); | ||
|
||
return $rep; | ||
} | ||
|
||
$tooltipLayers = $lproj->getTooltipLayers(); | ||
$layerName = $qgisLayer->getName(); | ||
|
||
if (isset($tooltipLayers->{$layerName}, $tooltipLayers->{$layerName}->{'template'})) { | ||
$tooltip = array('tooltip' => $tooltipLayers->{$layerName}->{'template'}); | ||
|
||
$data = \qgisExpressionUtils::replaceExpressionText( | ||
$qgisLayer, | ||
$tooltip, | ||
); | ||
|
||
$rep->data = $data; | ||
} | ||
|
||
return $rep; | ||
} | ||
|
||
/** | ||
* Get display expressions evaluated for the given layer and parameters. | ||
* | ||
* @urlparam string $REPOSITORY Name of the repository | ||
* @urlparam string $PROJECT Name of the project | ||
* @urlparam string $LAYERID Layer Id | ||
* @urlparam string $EXP_FILTER QGIS expression filter | ||
* @urlparam string $WITH_GEOMETRY If we need to get the features geometries | ||
* @urlparam string $FIELDS List of field names separated by comma | ||
* | ||
* @return jResponseJson geoJSON content | ||
*/ | ||
public function displayExpression() | ||
{ | ||
/** @var jResponseJson $rep */ | ||
$rep = $this->getResponse('json'); | ||
$content = array( | ||
'status' => 'error', | ||
'data' => null, | ||
'error' => 'An unexpected error occurred preventing to fetch the data', | ||
); | ||
$rep->data = $content; | ||
|
||
// Get project and repository, and check rights | ||
$project = $this->param('project'); | ||
$repository = $this->param('repository'); | ||
$layerId = trim($this->param('layerId', '')); | ||
$withGeometry = trim($this->param('with_geometry', 'false')); | ||
if (!in_array(strtolower($withGeometry), array('true', 'false'))) { | ||
$withGeometry = 'false'; | ||
} | ||
$fields = trim($this->param('fields', 'null')); | ||
$lproj = null; | ||
|
||
try { | ||
$lproj = lizmap::getProject($repository.'~'.$project); | ||
if (!$lproj) { | ||
$content['error'] = 'The lizmap project '.strtoupper($project).' does not exist !'; | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
} catch (\Lizmap\Project\UnknownLizmapProjectException $e) { | ||
jLog::logEx($e, 'error'); | ||
$content['error'] = 'The lizmap project '.strtoupper($project).' does not exist !'; | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
if (!$lproj->checkAcl()) { | ||
$content['error'] = jLocale::get('view~default.repository.access.denied'); | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
|
||
/** @var null|\qgisVectorLayer $qgisLayer */ | ||
$qgisLayer = $lproj->getLayer($layerId); | ||
|
||
if ($qgisLayer === null) { | ||
$content['error'] = 'The layer Id '.$layerId.' does not exist !'; | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
|
||
// Use Lizmap server plugin to evaluate the display expression & feature ID | ||
$expressions = array( | ||
// Get feature id | ||
'feature_id' => '@id', | ||
// Get display expression | ||
'display_expression' => 'display_expression()', | ||
); | ||
|
||
// Filter | ||
$exp_filter = trim($this->param('exp_filter', 'FALSE')); | ||
|
||
// Get the evaluated features for the given layer and parameters | ||
$getDisplayExpressions = qgisExpressionUtils::virtualFields( | ||
$qgisLayer, | ||
$expressions, | ||
$exp_filter, | ||
$withGeometry, | ||
$fields | ||
); | ||
|
||
// If the returned content is null, an error occurred | ||
// while getting the data from QGIS Server lizmap plugin | ||
if ($getDisplayExpressions === null) { | ||
$content['error'] = 'An error occurred while getting the display name for the features !'; | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
|
||
// Send the data on success | ||
$content = array( | ||
'status' => 'success', | ||
'data' => $getDisplayExpressions, | ||
'error' => null, | ||
); | ||
$rep->data = $content; | ||
|
||
return $rep; | ||
} | ||
} |
Oops, something went wrong.