I'm new to Geoserver and I'm trying to do a visualisation application with MVT, to achieve that I use MobilityDB which is an extension to the PostgreSQL database system and its spatial extension PostGIS. It allows temporal and spatio-temporal objects to be stored in the database, that is, objects whose attribute values and/or location evolves in time. I actually use a function that given a trip (which is an array of point with their timestamps) and the index of a tile I get all the point in the trip that go through this tile as a LINESTRING in tile coordinates and the timestamps of those points.
So I have a table with 2 columns one is a geometry in tile coordinates and the second one is an array of bigint(timestamps in unix epoch)
What I have done is creating the SQL View on Geoserver and put this query in
WITH bounds AS (
SELECT ST_TileEnvelope(14,8389,5497) AS geom
),
val AS (
SELECT asMVTGeom(trip, (bounds.geom)::stbox) as geom_times
FROM trips, bounds
),
mvtgeom AS(
SELECT (geom_times).geom, (geom_times).times
FROM val
)
select mvtgeom.geom, mvtgeom.times from mvtgeom where mvtgeom.geom is not null;
the first column is either a LINESTRING or MULTILIINESTRING and i convert the second column to text so it can be read by geoserver.
The problem here is that i the query return for example 500 rows I only get 135 elements in my response from geoserver sometime even if the query has a result I get 0 elements.
In my client application I run this code
import React, {useEffect, useState} from 'react';
import {render} from 'react-dom';
import DeckGL from '@deck.gl/react';
import axios from "axios";
import FPSStats from "react-fps-stats";
import {MVTLoader} from '@loaders.gl/mvt';
import {load} from '@loaders.gl/core';
import {MVTLayer, TripsLayer, TileLayer} from '@deck.gl/geo-layers';
import {StaticMap} from "react-map-gl";
import {BrowserRouter as Router, useLocation} from "react-router-dom";
const MAP_STYLE = 'https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json';
const INITIAL_VIEW_STATE = {
//berlin
longitude: 4.4,
latitude: 50.85,
zoom: 11,
minZoom: 0,
maxZoom: 23
};
// animation start and end in unix timestamp
const min_timestamp = 1180324800;
const max_timestamp = 1180339200;
function useQuery() {
return new URLSearchParams(useLocation().search);
}
export default function App({
trailLength = 180,
loopLength = max_timestamp-min_timestamp,
animationSpeed = 5
}) {
const [time, setTime] = useState(0);
const [animation] = useState({});
const animate = () => {
setTime(t => (t + animationSpeed) % loopLength);
animation.id = window.requestAnimationFrame(animate);
};
const toTimestamp = (strDate) => {
const dt = Date.parse(strDate);
return dt / 1000;
};
useEffect(
() => {
animation.id = window.requestAnimationFrame(animate);
return () => window.cancelAnimationFrame(animation.id);
},
[animation]
);
const onTileLoad = (tile) => {
console.log("=============================");
console.log("Tile coord",tile.id);
console.log("The content is ",tile)
console.log("==============================");
if(tile.content.length > 0) {
//console.log(tile);
}
const features = [];
if (tile.content.byteLength > 0 ){
for (const feature of tile.dataInWGS84) {
const ts = feature.properties.times;
const ts_final = ts.substring(1, ts.length - 1).split(",").map(t => parseInt(t, 10));
if (feature.geometry.type === "MultiLineString") {
let index = 0;
for (const coords of feature.geometry.coordinates) {
const ts_segment = ts_final.slice(index, index + coords.length)
features.push({
...feature,
geometry: {type: "LineString", coordinates: coords},
properties: {times: ts_segment}
});
index = coords.length;
}
} else {
features.push({...feature, properties: {times: ts_final}});
}
}
console.log("Features ",features)
tile.content = features;
}
}
const data = "http://localhost:8080/geoserver/wms?service=WMS&version=1.3.0&request=GetMap&" +
"layers=PostGIS:blabla&bbox=-180,-90,180,90&width=1024&" +
"height=1024&format=application/vnd.mapbox-vector-tile&crs=EPSG:3857&" +
"viewparams=z:{z};x:{x};y:{y}";
const layer = new MVTLayer({
id: 'trips',
data,
loader : MVTLoader,
loadOptions : {
coordinates: "wgs84"
},
binary : false,
onTileLoad : onTileLoad,
minZoom: 0,
maxZoom: 23,
lineWidthMinPixels: 1,
currentTime : 15900000,
/*
renderSubLayers: props => {
return new TripsLayer(props, {
data: props.data,
getPath: d => d.geometry.coordinates,
getTimestamps : d => d.properties.times,
opacity: 0.5,
widthMinPixels: 2,
rounded: true,
trailLength,
});
}
*/
})
return (
<DeckGL
layers={[layer]}
initialViewState={INITIAL_VIEW_STATE}
controller={true}
>
<StaticMap mapStyle={MAP_STYLE} />
</DeckGL>
);
}
export function renderToDOM(container) {
render(<Router><App /><FPSStats /></Router>, container);
}
I use this request but I don't know if when I use the application/vnd.mapbox-vector-tile the geometry should already be in tile coordinates or not.
Thank you in advance for your help don't hesitate ask if you need more details. It is the first time I do such a request