Mesh Map
Overview
The Mesh Map prefab takes a GeoJson and d3-geo projection input and generates a Extruded Polygon Mesh for each polygon or multi-polygon GeoJSON feature. This prefab also utilize topoJson for Mesh simplification. The createMeshMap() method returns an instance of the MeshMap object which contains the relevant properties for the Mesh creation and manipulation. Each polygon metadata.data property will be set with the data from its features.properties GeoJSON.
Usage
js
//name (required), options (geojson required), babylon scene (optional)
//Returns instance of MeshMap
let map = anu.createMeshMap(name: String, options: {}, scene: BABYLON.Scene);
//The transformed input d3-geo projection
let projection = map.projection
//A selection object containing all the generated polygons
let selection = map.selection
Options
Option | Value | Default |
---|---|---|
geoJson (required) | a valid geoJSON file | null |
projection | (d3.GeoProjection) such as d3.geoAlbers() | d3.geoAlbers() |
size | ([number, number]) an array with the max height and width of the projection | [10,10] |
transform | ([number, number]) and array with the center coordinates of the projection in render space | [0,0] |
simplification | (number) the simplification factor relative to the projection size | 0 |
depth | (number) the height of the extruded the polygons | 1 |
cot | (Babylon.Node) The node to be the parent of all the polygons, if not set a transform node "meshMapCOT" will be created | TransformNode('meshMapCOT') |
Methods and Properties
Property / Method | Description |
---|---|
projection | the transformed d3.geoProjection which can be used map position from longitude and latitude as projection([lon, lat]) |
selection | a selection object containing all the generated polygons with their respective geoJSON properties data binded to them |
Examples
js
// SPDX-License-Identifier: Apache-2.0
// Copyright : J.P. Morgan Chase & Co.
import * as anu from '@jpmorganchase/anu';
import * as BABYLON from '@babylonjs/core';
import * as d3 from 'd3';
import data from './data/airports.csv';
import geoJ from './data/gz_2010_us_040_00_5m.json';
//Create and export a function that takes a Babylon engine and returns a Babylon Scene
export function meshMap(engine) {
//Create an empty Scene
const scene = new BABYLON.Scene(engine);
//Add some lighting
new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 10, 0), scene);
//Add a camera that rotates around the origin and adjust its properties
const camera = new BABYLON.ArcRotateCamera('Camera', 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene);
camera.position = new BABYLON.Vector3(0, 1.25, -1);
camera.wheelPrecision = 20;
camera.minZ = 0;
camera.attachControl(true);
//Use the Mesh Map prefab to create 3D meshes based on GeoJSON data
let meshMap = anu.createMeshMap('meshMap', { geoJson: geoJ,
depth: 0.05,
projection: d3.geoAlbers().reflectY(true), //Flip the Y so we don't have to rotate it later
size: [2, 2],
simplification: 0.000001 }); //Higher value = less vertices = better performance but less detail
//The prefab contains a Selection that consists of the Meshes for each polygon in our GeoJSON (i.e., the US states)
let states = meshMap.selection;
//Create a D3 scale for color, using Anu helper functions map scale outputs to StandardMaterial objects based on the 'schemecategory10' palette from D3
let scaleC = d3.scaleOrdinal(anu.ordinalChromatic('d310').toStandardMaterial());
//Assign each state a Material (and therefore, their color)
states.material((d) => scaleC(d.NAME));
//We use Mesh instancing here for better performance, first we create a Mesh that serves as the root Node
let rootSphere = anu.create('sphere', 'sphere', { diameter: 0.003 });
rootSphere.isVisible = false;
rootSphere.registerInstancedBuffer('color', 4); //We need an InstancedBuffer to set the color of instances
//Select our map object as a Selection object which will serve as our CoT
let chart = anu.selectName('meshMap', scene);
//Create instanced sphere meshes from our rootSphere as children of our CoT for each row of our data and set their visual encodings using method chaining
let spheres = chart.bindInstance(rootSphere, data)
.positionX((d) => meshMap.projection([d.longitude, d.latitude])[0]) //The meshMap prefab object contains a projection() function that will convert
.positionZ((d) => meshMap.projection([d.longitude, d.latitude])[1]) //a longitude and latitude into the correct position on the meshMap
.setInstancedBuffer('color', new BABYLON.Color4(0,0,0,1));
return scene;
}