Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add source projection information to map-sources #787

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 36 additions & 28 deletions src/gm3/actions/mapSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ import {
} from "../components/map/layers/wfs";
import { EDIT_LAYER_NAME } from "../defaults";

import * as util from "../util";
import {
parseBoolean,
getTagContents,
getXmlTextContents,
getMapSourceName,
getLayerName,
} from "../util";

let MS_Z_INDEX = 100000;

Expand Down Expand Up @@ -135,7 +141,7 @@ function parseProperties(msXml) {
for (let x = 0, xx = options.length; x < xx; x++) {
propDef.options.push({
value: options[x].getAttribute("value"),
label: util.getXmlTextContents(options[x]),
label: getXmlTextContents(options[x]),
});
}
}
Expand Down Expand Up @@ -174,8 +180,8 @@ export const favoriteLayer = createAction(
* @returns Object defining the map source
*/
function mapServerToDestType(msXml, conf, destType) {
let urls = util.getTagContents(msXml, "url", true);
const mapfile = util.getTagContents(msXml, "file", true)[0];
let urls = getTagContents(msXml, "url", true);
const mapfile = getTagContents(msXml, "file", true)[0];

// if the url is null then default to the
// mapserver url.
Expand Down Expand Up @@ -220,11 +226,13 @@ function mapServerToWFS(msXml, conf) {

/* MapServer has a pretty major bug, it will not properly
* reproject bounding boxes for non-WGS84 layers when doing
* WFS queries. This tells the query engine in the map component,
* to use an internal work-around ... aka ... "hack".
* WFS queries.
* This forces using a query of projection of 4326 if it
* otherwise not set
*/
wfsConf.wgs84Hack = true;

if (!wfsConf.srcProj) {
wfsConf.srcProj = "EPSG:4326";
}
return wfsConf;
}

Expand All @@ -235,21 +243,22 @@ export function addFromXml(xml, config) {
// initialize the map source object.
const mapSource = {
name: xml.getAttribute("name"),
urls: util.getTagContents(xml, "url", true),
urls: getTagContents(xml, "url", true),
type: xml.getAttribute("type"),
label: xml.getAttribute("title"),
opacity: xml.getAttribute("opacity"),
zIndex: xml.getAttribute("z-index"),
queryable: util.parseBoolean(xml.getAttribute("queryable"), true),
queryable: parseBoolean(xml.getAttribute("queryable"), true),
// assume layers are printable
printable: util.parseBoolean(xml.getAttribute("printable"), true),
printable: parseBoolean(xml.getAttribute("printable"), true),
refresh: null,
layers: [],
transforms: {},
params: {},
config: {},
properties: [],
idProperty: "_uuid",
srcProj: xml.getAttribute("src-proj"),
};

// handle setting up the zIndex
Expand Down Expand Up @@ -315,9 +324,9 @@ export function addFromXml(xml, config) {

const layer = {
name: layerXml.getAttribute("name"),
on: util.parseBoolean(layerXml.getAttribute("status")),
favorite: util.parseBoolean(layerXml.getAttribute("favorite")),
selectable: util.parseBoolean(layerXml.getAttribute("selectable")),
on: parseBoolean(layerXml.getAttribute("status")),
favorite: parseBoolean(layerXml.getAttribute("favorite")),
selectable: parseBoolean(layerXml.getAttribute("selectable")),
label: layerTitle ? layerTitle : mapSource.label,
templates: {},
legend: null,
Expand All @@ -332,14 +341,14 @@ export function addFromXml(xml, config) {
if (legends.length > 0) {
layer.legend = {
type: legends[0].getAttribute("type"),
contents: util.getXmlTextContents(legends[0]),
contents: getXmlTextContents(legends[0]),
};
}

// pull in an HTML attribution as available.
const attribution = layerXml.getElementsByTagName("attribution");
if (attribution.length > 0) {
layer.attribution = util.getXmlTextContents(attribution[0]);
layer.attribution = getXmlTextContents(attribution[0]);
}

const templates = layerXml.getElementsByTagName("template");
Expand All @@ -351,7 +360,7 @@ export function addFromXml(xml, config) {

const templateSrc = templateXml.getAttribute("src");
const templateAlias = templateXml.getAttribute("alias");
const autoTemplate = util.parseBoolean(templateXml.getAttribute("auto"));
const autoTemplate = parseBoolean(templateXml.getAttribute("auto"));
if (templateAlias) {
templateDef = {
type: "alias",
Expand All @@ -369,17 +378,16 @@ export function addFromXml(xml, config) {
} else {
templateDef = {
type: "local",
contents: util.getXmlTextContents(templateXml),
contents: getXmlTextContents(templateXml),
};
}
templateDef.highlight =
util.parseBoolean(templateXml.getAttribute("highlight"), true) !==
false;
parseBoolean(templateXml.getAttribute("highlight"), true) !== false;
layer.templates[templateName] = templateDef;
}

// check to see if there are any style definitions
const style = util.getTagContents(layerXml, "style", false);
const style = getTagContents(layerXml, "style", false);
if (style && style.length > 0) {
// convert to JSON
try {
Expand All @@ -394,7 +402,7 @@ export function addFromXml(xml, config) {
}

// check to see if there are any filter definitions
const filter = util.getTagContents(layerXml, "filter", false);
const filter = getTagContents(layerXml, "filter", false);
if (filter && filter.length > 0) {
// convert to JSON
try {
Expand Down Expand Up @@ -526,8 +534,8 @@ export function getActiveMapSources(mapSources, onlyPrintable = false) {
}

export function getLayerFromPath(mapSources, path) {
const mapSourceName = util.getMapSourceName(path);
const layerName = util.getLayerName(path);
const mapSourceName = getMapSourceName(path);
const layerName = getLayerName(path);

return getLayer(mapSources, {
mapSourceName: mapSourceName,
Expand Down Expand Up @@ -754,11 +762,11 @@ export function removeFeature(path, feature) {
return (dispatch, getState) => {
const mapSources = getState().mapSources;
const layer = getLayerFromPath(mapSources, path);
const layerSrcName = util.getMapSourceName(path);
const layerSrcName = getMapSourceName(path);

let mapSourceName = layerSrcName;
if (layer && layer.queryAs && layer.queryAs.length > 0) {
mapSourceName = util.getMapSourceName(layer.queryAs[0]);
mapSourceName = getMapSourceName(layer.queryAs[0]);
}

const mapSource = getState().mapSources[mapSourceName];
Expand Down Expand Up @@ -945,11 +953,11 @@ export function saveFeature(path, feature) {
return (dispatch, getState) => {
const mapSources = getState().mapSources;
const layer = getLayerFromPath(mapSources, path);
const layerSrcName = util.getMapSourceName(path);
const layerSrcName = getMapSourceName(path);

let mapSourceName = layerSrcName;
if (layer && layer.queryAs && layer.queryAs.length > 0) {
mapSourceName = util.getMapSourceName(layer.queryAs[0]);
mapSourceName = getMapSourceName(layer.queryAs[0]);
}

const mapSource = getState().mapSources[mapSourceName];
Expand Down
33 changes: 27 additions & 6 deletions src/gm3/components/map/layers/vector.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ import {
import GML2Format from "ol/format/GML2";
import GeoJSONFormat from "ol/format/GeoJSON";
import EsriJsonFormat from "ol/format/EsriJSON";
import { tile, bbox } from "ol/loadingstrategy";
import { tile, bbox, all } from "ol/loadingstrategy";
import VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import { createXYZ } from "ol/tilegrid";
import { transformExtent } from "ol/proj";
import { getEditStyle } from "./edit";
import { EDIT_LAYER_NAME } from "../../../defaults";
import { getQueryProjection } from "./wfs";

// WARNING! This is a monkey patch in order to
// allow rendering labels outside of a polygon's
Expand Down Expand Up @@ -76,9 +78,21 @@ function defineSource(mapSource) {
format = GeoJSONFormat;
}

const strategyName = mapSource.config?.strategy;
let strategy = bbox;
if (strategyName === "all") {
strategy = all;
}

// TODO: Ensure this gets the real map projection when
// the code supports alternative projections.
const mapProjection = "EPSG:3857";
const queryProjection = getQueryProjection(mapSource, mapProjection);

return {
format: new format({}),
projection: "EPSG:4326",
format: new format({
srsName: queryProjection,
}),
url: function (extent) {
if (typeof mapSource.params.typename === "undefined") {
console.error(
Expand All @@ -89,19 +103,26 @@ function defineSource(mapSource) {
const urlParams = Object.assign(
{},
{
srsname: "EPSG:3857",
srs: queryProjection,
outputFormat: outputFormat,
service: "WFS",
version: "1.1.0",
request: "GetFeature",
bbox: extent.concat("EPSG:3857").join(","),
},
mapSource.params
);

if (strategy === bbox) {
const queryExtent = transformExtent(
extent,
mapProjection,
queryProjection
);
urlParams.bbox = queryExtent;
}
return joinUrl(mapSource.urls[0], urlParams);
},
strategy: bbox,
strategy,
};
} else if (mapSource.type === "geojson") {
return {
Expand Down
20 changes: 12 additions & 8 deletions src/gm3/components/map/layers/wfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ import * as proj from "ol/proj";

import { featureToJson, transformFeatures } from "../../../util";

export function getQueryProjection(mapSource, mapProjection) {
return mapSource.config?.srs || mapSource.srcProj || mapProjection;
}

function chainFilters(operator, filters) {
let chainedFilters = null;
if (filters.length > 1) {
Expand Down Expand Up @@ -99,13 +103,10 @@ export function buildWfsQuery(
) {
const geomField = getGeometryName(mapSource);

// the internal storage mechanism requires features
// returned from the query be stored in 4326 and then
// reprojected on render.
let queryProjection = mapProjection;
if (mapSource.wgs84Hack) {
queryProjection = new proj.get("EPSG:4326");
}
// The WFS source may be in a different projection than the map
const queryProjection = new proj.get(
getQueryProjection(mapSource, mapProjection)
);

const filters = [];
if (query.selection && query.selection.length > 0) {
Expand Down Expand Up @@ -169,6 +170,7 @@ export function wfsGetFeatures(
mapProjection,
outputFormat
);
const queryProjection = getQueryProjection(mapSource, mapProjection);

// TODO: check for params and properly join to URL!

Expand All @@ -181,6 +183,8 @@ export function wfsGetFeatures(
const gmlFormat = new GML2Format();

let features = gmlFormat.readFeatures(response).map((feature) => {
feature.getGeometry().transform(queryProjection, "EPSG:4326");

const jsonFeature = featureToJson(feature);
jsonFeature.properties = {
...jsonFeature.properties,
Expand All @@ -202,7 +206,7 @@ function wfsTransact(mapSource, mapProjection, inFeatures) {
const options = {
featurePrefix: typeParts[0],
featureType: typeParts[1],
srsName: config.srs || "EPSG:3857",
srsName: getQueryProjection(mapSource, mapProjection),
};

if (config["namespace-uri"]) {
Expand Down
12 changes: 5 additions & 7 deletions src/gm3/query/wfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import GML2Format from "ol/format/GML2";
import { applyPixelTolerance } from "./util";
import { transformFeatures, formatUrlParameters } from "../util";

import { buildWfsQuery } from "../components/map/layers/wfs";
import {
buildWfsQuery,
getQueryProjection,
} from "../components/map/layers/wfs";

export const wfsGetFeatureQuery = (layer, mapState, mapSource, query) => {
// the internal storage mechanism requires features
// returned from the query be stored in 4326 and then
// reprojected on render.
const queryProjection = mapSource.wgs84Hack
? "EPSG:4326"
: mapState.projection;
const queryProjection = getQueryProjection(mapSource, mapState.projection);

// check for the outputFormat based on the params
let outputFormat = "text/xml; subtype=gml/2.1.2";
Expand Down