Tools for geospatial data visualization with custom 3D models - data-visualization

I need a tool that does geospatial data visualization, but which will also allow me to import, or to create custom 3D models (e.g. to import .gltf files).
Kepler.gl seems a great choice for geospatial data visualization, yet I couldn't find the way to import certain .gltf file and I am not sure this is even possible in kepler.gl.
Any recommendations?

Have you explored the latest version of threebox?? It enables you to add as many models and 3D layers as you want on top of Mapbox using their support for 3D objects through CustomLayerInterface with only a few lines of code
map.on('style.load', function () {
map.addLayer({
id: 'custom_layer',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, mbxContext) {
window.tb = new Threebox(
map,
mbxContext,
{ defaultLights: true }
);
var options = {
obj: '/3D/soldier/soldier.glb',
type: 'gltf',
scale: 1,
units: 'meters',
rotation: { x: 90, y: 0, z: 0 } //default rotation
}
tb.loadObj(options, function (model) {
soldier = model.setCoords(origin);
tb.add(soldier);
})
},
render: function (gl, matrix) {
tb.update();
}
});
})
And you can do much more...
- 3D models built-in and custom animations
- Full raycast support MouseOver/Mouseout, Selected, Drag&Drop, Drag&Rotate, Wireframe
- CSS2D Tooltips and Labels that consider altitude
- Three.js and Mapbox cameras sync with depth adjustment
- Include geolocated models of monuments with sunlight & shadows build-in support
- Optimized to load thousands of 3D objects

Related

How to use inner camera in gltf in aframe?

I have a gltf model, which contains cameras, models and camera animations. After loading, they become an gltf entity. I can't use secondcamera el. SetAttribute ('camera ','active', true ')" to change camera. How can I use the camera in it.
This can be modified in three. JS
this.content.traverse((node) => {
if (node.isCamera && node.name === name) {
this.activeCamera = node;
}
});
this.renderer.render( this.scene, this.activeCamera )
but, how to use inner camera in gltf in aframe?
You could keep the reference to the camera:
var model_camera = null;
// wait until the model is loaded
entity.addEventListener("model-loaded", e => {
const mesh = entity.getObject3D("mesh");
mesh.traverse(node => {
// assuming there is one camera
if (node.isCamera) model_camera = node;
})
})
and when you need to use it, just substitute the active camera in the scene.camera property:
entity.sceneEl.camera = model_camera;
Check it out in this example with a model containing two different cameras.
Afaik there is no cleanup involved, the look-controls or wasd-controls will still be working as long as you don't manually disable them when switching cameras.
The camera system has a function for swapping active cameras, but you would need to add <a-entity> wrappers for the camera references (as the system tries to perform getObject3D('camera') on the provided entity).

How to limit search results to an extent with Esri Javascript map?

I believe by default the 4.13 Esri Javascript map will search addresses by the current map view extent. The issue is that if the user zooms in or out too far, the search results return addresses VERY far away. Here is my code:
function initESRIMap() {
require(["esri/Map", "esri/views/MapView", "esri/widgets/Search", "esri/layers/FeatureLayer", "esri/widgets/Popup", "esri/geometry/Extent", "esri/geometry/Geometry"], function (
Map,
MapView,
Search,
FeatureLayer,
Popup,
Extent,
Geometry
) {
var esriMap = new Map({
basemap: "streets",
});
var esriView = new MapView({
container: "map-div",
map: esriMap,
center: LatLong,
zoom: 11,
});
var search = new Search({
view: esriView,
});}
I want to be able to get the same search results REGARDLESS of my map view location. BUT limit results to a specific area. Therefore if I'm viewing another country I'll still see search results from my extent.
A search widget can be customized to use custom sources, and a custom source can be customized to use a filter, which can include a map extent.
For example, let's define a custom SearchSource - we'll just use the same search endpoint as the standard ArcGIS World Geocoder service, but we'll add a filter:
const source = {
locator: new Locator({
url: "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"
}),
filter: {
geometry: new Extent({
xmax: -12921954.804910611,
xmin: -13126806.04071496,
ymax: 3909898.0736186495,
ymin: 3801204.619397087,
spatialReference: {
wkid: 102100
}
})
},
maxSuggestions: 10
};
Now when we're defining our search widget, we'll include this in the source property array, and we'll turn off includeDefaultSources so that the original, unbounded source, is not used:
const search = new Search({
view,
includeDefaultSources: false,
sources: [source]
});
Working Codesandbox
In this example, I set the extent in the filter to be around the area of san diego / tijuana. Wherever you pan or zoom on the map, you'll still only get results from that area. For example, move the map over to seattle, or china, or whatever, and search for something generic ("park", "road", whatever), and you'll see that no matter what the map's extent is, the search results will be limited to what you put in the search source's filter.
Note this answer was written with 4.18.

Problem painting a map with Openlayers using Vue

I'm writing an application in Vue that will have a map in it. I want to add some points in that map. The code relevant to the map is,
<div>
<vl-map :load-tiles-while-animating="true" :load-tiles-while-interacting="true" data-projection="EPSG:4326" style="height: 400px">
<vl-view :zoom.sync="zoom" :center.sync="center" :rotation.sync="rotation"></vl-view>
<vl-layer-tile>
<vl-source-osm></vl-source-osm>
</vl-layer-tile>
<vl-layer-vector>
<vl-source-vector :features="points"></vl-source-vector>
</vl-layer-vector>
</vl-map>
</div>
Here points is part of data points: []
If I write the points directly in data everything works.
Like,
points: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0.0, 0.0]
},
properties: {}
]
shows a point in [0, 0].
However, I need to use a method that will call several APIs to find out the points that I need to show. It's when I write the code to prepare the points to have the correct value when everything stops working. I'm writing this code in the mounted section.
async calculatePoints () {
this.points = // points as I want them to be
}
But this is not working (although some few times works). Any idea what is going on here or which is the best way to handle this?

Updating a chart with new data in App SDK 2.0

I am using a chart to visualize data in a TimeboxScopedApp, and I want to update the data when scope changes. The more brute-force approach of using remove() then redrawing the chart as described here leaves me with an overlaid "Loading..." mask, but otherwise works. The natural approach of using the Highchart native redraw() method would be my preference, only I don't know how to access the actual Highchart object and not the App SDK wrapper.
Here's the relevant part of the code:
var chart = Ext.getCmp('componentQualityChart');
if (chart) {
var chartCfg = chart.getChartConfig();
chartCfg.xAxis.categories = components;
chart.setChartConfig(chartCfg);
chart.setChartData(data);
chart.redraw(); // this doesn't work with the wrapper object
} else { // draw chart for the first time
How do I go about redrawing the chart with the new data?
Assuming chart (componentQualityChart) is an instance of Rally.ui.chart.Chart, you can access the HighCharts instance like this:
var highcharts = chart.down('highchart').chart;
// Now you have access to the normal highcharts interface, so
// you could change the xAxis
highcharts.xAxis[0].setCategories([...], true);
// Or you could change the series data
highcharts.series[0].data.push({ ... }); //Add a new data point
// Or pretty much anything else highcharts lets you do
Using _unmask() removes the overlaid "Loading.." mask
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
//....
},
chartData: {
categories: scheduleStateGroups,
series: [
{
//...
}
]
}
}
);
this.down('#myChart')._unmask();

How to animate Google Maps API KML Ground Overlay

Two questions:
What is the best way to create a smooth animation through 12 KML Files through google maps API V2?
How can I integrate a fadeIn() / fadeOut() to smoothly transtition between these KML files?
I have experimented some with setTimeouts() with 2 of my KML filed but haven't figured out a smooth or consistent way to animate between them. Code is below.
function animate () {
function series_1 () {
geoXml = new GGeoXml("lake/colors_test.kml");
map.addOverlay(geoXml);
setTimeout("map.removeOverlay(geoXml)", 5000);
}
function series_2 () {
geoXml1 = new GGeoXml("lake/colors_test_1.kml");
map.addOverlay(geoXml1);
setTimeout("map.removeOverlay(geoXml1)", 5000);
}
series_1();
series_2();
}
animate();
I think you'll need to apply fading to the underlying images:
$("#mapContent").find("img[src*=\"lyrs=kml\"]").fadeOut();
This is for the V3 API, you might need a different selector for the V2 API.
I'm assuming the map is created with
map = new google.maps.Map document.getElementById("mapContent");
jQuery also has a fadeIn() method, however it gets tricky because the images are probably recreated when you add a new KML layer. You'll need to find a way to set their visibility to zero when they are created.