Skip to content

Commit

Permalink
Merge pull request #1029 from dbauszus-glx:mvt-geom-prop
Browse files Browse the repository at this point in the history
wkt_properties feature format and mvt queries
  • Loading branch information
RobAndrewHurst authored Dec 18, 2023
2 parents c8164be + 89a1a33 commit 995b4e2
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 92 deletions.
13 changes: 12 additions & 1 deletion lib/layer/Style.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,18 @@ export default layer => {
if (Styles) return Styles
}

feature.properties = feature.getProperties()
if (layer.featuresObject) {

let id = feature.get('id').toString()

feature.properties = layer.featuresObject[id]

if (!feature.properties) return;

} else {

feature.properties = feature.getProperties()
}

// Geojson features have a properties property
if (feature.properties.properties) {
Expand Down
155 changes: 138 additions & 17 deletions lib/layer/format/mvt.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default layer => {
console.warn(`Layer ${layer.key} must be set to use SRID 3857.`)
return;
}

// Assign empty style object if nullish.
layer.style ??= {}

Expand All @@ -25,9 +25,13 @@ export default layer => {

layer.reload = () => {

if (layer.wkt_properties) {
changeEndLoad(layer)
return;
}

layer.source.clear()
layer.source.refresh()
layer.tilesLoaded = []
layer.featureSource.refresh()
}

Expand All @@ -44,20 +48,87 @@ export default layer => {
cacheSize: 0,
tileUrlFunction
})

// Define source for mvt layer.
layer.source = new ol.source.VectorTile({
format: new ol.format.MVT(),
transition: 0,
cacheSize: 0,
tileUrlFunction
transition: layer.transition,
cacheSize: layer.cacheSize
})

function tileUrlFunction(tileCoord) {
// Assign wkt properties load method.
if (layer.wkt_properties) {
layer.source.setTileUrlFunction(wktTileUrlFunction(layer))
layer.mapview.Map.getTargetElement().addEventListener('changeEnd', () => changeEndLoad(layer));

} else {

layer.source.setTileUrlFunction(tileUrlFunction(layer))
}

layer.L = new ol.layer.VectorTile({
key: layer.key,
source: layer.source,
renderBuffer: 200,
//renderMode: 'vector',
zIndex: layer.style?.zIndex || 1,
style: mapp.layer.Style(layer)
})
}

function wktTileUrlFunction(layer) {

return tileCoord => {

const table = layer.tableCurrent()

if ((!table || !layer.display) && !layer.clones?.size) return layer.source.clear()
// The layer has no data for this zoom level.
if (!table) {
layer.source.clear();
return;
}

// The layer does not display and doesn't have clones.
if (!layer.display && !layer.clones?.size) {
layer.source.clear();
return;
}

const geom = layer.geomCurrent()

const url = `${layer.mapview.host}/api/query?${mapp.utils.paramString({
template: 'mvt',
z: tileCoord[0],
x: tileCoord[1],
y: tileCoord[2],
locale: layer.mapview.locale.key,
layer: layer.key,
srid: layer.mapview.srid,
table,
geom
})}`

return url
}
}

function tileUrlFunction(layer) {

return tileCoord => {

const table = layer.tableCurrent()

// The layer has no data for this zoom level.
if (!table) {
layer.source.clear();
return;
}

// The layer does not display and doesn't have clones.
if (!layer.display && !layer.clones?.size) {
layer.source.clear();
return;
}

const geom = layer.geomCurrent()

Expand All @@ -76,7 +147,6 @@ export default layer => {
y: tileCoord[2],
locale: layer.mapview.locale.key,
layer: layer.key,
srid: layer.mapview.srid,
table,
geom,
filter: layer.filter?.current,
Expand All @@ -86,13 +156,64 @@ export default layer => {
return url
}

layer.L = new ol.layer.VectorTile({
key: layer.key,
source: layer.source,
renderBuffer: 200,
//renderMode: 'vector',
zIndex: layer.style?.zIndex || 1,
style: mapp.layer.Style(layer)
})
}

function changeEndLoad(layer) {

layer.xhr?.abort()

const table = layer.tableCurrent()

if ((!table || !layer.display) && !layer.clones?.size) return layer.source.clear()

const geom = layer.geomCurrent()

// Create a set of feature properties for styling.
layer.params.fields = [...new Set([
Array.isArray(layer.style.theme?.fields) ?
layer.style.theme.fields : layer.style.theme?.field,
layer.style.theme?.field,
layer.style.label?.field
].flat().filter(field => !!field))]

const bounds = layer.mapview.getBounds()

// Assign current viewport if queryparam is truthy.
let viewport = [bounds.west, bounds.south, bounds.east, bounds.north, layer.mapview.srid];

// Assign current viewport if queryparam is truthy.
let z = layer.mapview.Map.getView().getZoom();

layer.xhr = new XMLHttpRequest()

layer.xhr.responseType = 'json'

layer.xhr.onload = e => {

layer.featuresObject = {}

if (!e.target?.response) {
layer.L.changed()
return;
}

mapp.utils.featureFormats.wkt_properties(layer, e.target.response)

layer.L.changed()
}

layer.xhr.open('GET', `${layer.mapview.host}/api/query?${mapp.utils.paramString({
template: 'wkt',
locale: layer.mapview.locale.key,
layer: layer.key,
table,
geom,
no_geom: true,
viewport,
z,
filter: layer.filter?.current,
...layer.params
})}`)

layer.xhr.send()
}
137 changes: 79 additions & 58 deletions lib/utils/featureFormats.mjs
Original file line number Diff line number Diff line change
@@ -1,100 +1,121 @@
function initializeFieldStats(layer) {
if (layer.style?.theme?.field_stats) {
layer.style.theme.updated = true;
layer.style.theme.field_stats[layer.style.theme.field] = {
values: []
};
}
if (layer.style?.theme?.field_stats) {
layer.style.theme.updated = true;
layer.style.theme.field_stats[layer.style.theme.field] = {
values: []
};
}
}

export function geojson(layer, features) {

const formatGeojson = new ol.format.GeoJSON

initializeFieldStats(layer);
const formatGeojson = new ol.format.GeoJSON

return features.map((feature) => {
initializeFieldStats(layer);

const properties = feature.properties
return features.map((feature) => {

if (layer.style?.theme?.field_stats) {
const properties = feature.properties

layer.style.theme.field_stats[layer.style.theme.field].values.push(parseFloat(properties[layer.style.theme.field]));
}
if (layer.style?.theme?.field_stats) {

return new ol.Feature({
id: feature.id,
geometry: formatGeojson.readGeometry(feature.geometry, {
dataProjection: 'EPSG:' + layer.srid,
featureProjection: 'EPSG:' + layer.mapview.srid,
}),
properties
})
layer.style.theme.field_stats[layer.style.theme.field].values.push(parseFloat(properties[layer.style.theme.field]));
}

return new ol.Feature({
id: feature.id,
geometry: formatGeojson.readGeometry(feature.geometry, {
dataProjection: 'EPSG:' + layer.srid,
featureProjection: 'EPSG:' + layer.mapview.srid,
}),
properties
})

})
}

export function wkt(layer, features) {

const formatWKT = new ol.format.WKT
const formatWKT = new ol.format.WKT

initializeFieldStats(layer);

return features.map((feature) => {

const properties = {}

initializeFieldStats(layer);
// Assign field key and value to properties object
layer.params.fields?.forEach((field, i) => {

return features.map((feature) => {
if (layer.style?.theme?.field_stats?.[field]) {

const properties = {}
layer.style?.theme?.field_stats?.[field].values.push(parseFloat(feature[i + 2]));
}

// Assign field key and value to properties object
layer.params.fields?.forEach((field, i) => {
properties[field] = feature[i + 2]
})

// Return feature from geometry with properties.
return new ol.Feature({
id: feature.shift(),
geometry: formatWKT.readGeometry(feature.shift(), {
dataProjection: 'EPSG:' + layer.srid,
featureProjection: 'EPSG:' + layer.mapview.srid,
}),
properties
})

})
}

if (layer.style?.theme?.field_stats?.[field]) {
export function wkt_properties(layer, features) {

layer.style?.theme?.field_stats?.[field].values.push(parseFloat(feature[i + 2]));
}
initializeFieldStats(layer);

properties[field] = feature[i + 2]
})
for (const feature of features) {

// Return feature from geometry with properties.
return new ol.Feature({
id: feature.shift(),
geometry: formatWKT.readGeometry(feature.shift(), {
dataProjection: 'EPSG:' + layer.srid,
featureProjection: 'EPSG:' + layer.mapview.srid,
}),
properties
})
const properties = {}

// Assign field key and value to properties object
layer.params.fields?.forEach((field, i) => {

if (layer.style?.theme?.field_stats?.[field]) {

layer.style?.theme?.field_stats?.[field].values.push(parseFloat(feature[i + 1]));
}

properties[field] = feature[i + 1]
})

layer.featuresObject[feature.shift()] = properties
}
}

export function cluster(layer, features) {

layer.max_size = 1
layer.max_size = 1

return features.map((vals, i) => {
return features.map((vals, i) => {

const geometry = new ol.geom.Point(vals.shift())
const geometry = new ol.geom.Point(vals.shift())

const count = vals.shift()
const count = vals.shift()

layer.max_size = layer.max_size > count ? layer.max_size: count;
layer.max_size = layer.max_size > count ? layer.max_size : count;

const id = vals.shift()
const id = vals.shift()

const properties = {count}

layer.params.fields.forEach((field, i) => {
properties[field] = vals[i]
})
const properties = { count }

return new ol.Feature({
id,
geometry,
...properties
})
layer.params.fields.forEach((field, i) => {
properties[field] = vals[i]
})

return new ol.Feature({
id,
geometry,
...properties
})

})
}
Loading

0 comments on commit 995b4e2

Please sign in to comment.