“This is the 22nd day of my participation in the First Challenge 2022. For details: First Challenge 2022”
Introduction to the
Drill-down sounds like a pretty cool technique, but it’s pretty simple to implement once you get the hang of it.
Implementation approach
- Obtain national data in GeoJSON format and draw Chinese map scenes.
- Monitor click events and judge the provinces and cities of drilling.
- Gets the province clicked
GeoJSON
Format the data to draw the province map scene. - Switch scenes to show province maps.
Mapping China
- The previous chapters have already been drawn, so only a few minor changes are needed.
- In the common method before
projection()
The function is a global method, and the center point of the map is to be modified after drilling, so it is passed in as a parameter. - to
drawExtrudeMesh()
Method generates solid geometry to add, uniquely identified.properties
Properties.
The mouse to pick up
- use
.Raycaster()
Ray tracing, listening for mouse events.
- Create common method normalized coordinates.
// compute the mouse coordinates starting with the canvas at (0,0)
function getCanvasRelativePosition(event) {
const rect = canvas.getBoundingClientRect()
return {
x: ((event.clientX - rect.left) * canvas.width) / rect.width,
y: ((event.clientY - rect.top) * canvas.height) / rect.height
}
}
/** * Get mouse normalized coordinates in three.js ** /
function setPickPosition(event) {
let pickPosition = { x: 0.y: 0 }
// start with canvas (0,0) after calculation
const pos = getCanvasRelativePosition(event)
// Data normalization
pickPosition.x = (pos.x / canvas.width) * 2 - 1
pickPosition.y = (pos.y / canvas.height) * -2 + 1
return pickPosition
}
Copy the code
- Listen for mouse click events.
// Monitor the mouse
window.addEventListener('click', onRay)
// Global objects
let lastPick = null
function onRay(event) {
let pickPosition = setPickPosition(event)
const raycaster = new THREE.Raycaster()
raycaster.setFromCamera(pickPosition, camera)
// Calculate the intersection of the object and the ray
const intersects = raycaster.intersectObjects([map], true)
// If the array is greater than 0, there are intersecting objects
if (intersects.length > 0) {
if (lastPick) {
if(lastPick.object.properties ! == intersects[0].object.properties) {
lastPick.object.material.color.set('yellow')
lastPick = null}}if (intersects[0].object.properties) {
intersects[0].object.material.color.set('blue')
}
lastPick = intersects[0]}else {
if (lastPick) {
/ / recovery
if (lastPick.object.properties) {
lastPick.object.material.color.set('yellow')
lastPick = null}}}}Copy the code
Draw provincial scenes
- The only difference is that the city of Chongqing is set as the center.
- Create a new scene and load the data to draw the map in the new scene.
- Province map coordinate position interval is small, use
.scale
Zoom in.
// With Chongqing municipality as the center
const projection2 = d3.geoMercator().center([106.557691.29.559296]).translate([0.0])
// Map of Chongqing
loader.load('./file/500000_full.json'.(data) = > {
const jsondata = JSON.parse(data)
operationData2(jsondata)
})
/ / scenario 2
const scene2 = new THREE.Scene()
const map2 = new THREE.Object3D()
// Parse the data
function operationData2(jsondata) {
// National information
const features = jsondata.features
features.forEach((feature) = > {
// A single province object
const province = new THREE.Object3D()
/ / address
province.properties = feature.properties.name
const coordinates = feature.geometry.coordinates
const color = 'yellow'
// const color = [' admin ', 'admin ']. Includes (feature.properties. Name)?
if (feature.geometry.type === 'MultiPolygon') {
// Multiple, polygon
coordinates.forEach((coordinate) = > {
// coordinate polygon data
coordinate.forEach((rows) = > {
const mesh = drawExtrudeMesh(rows, color, projection2)
const line = lineDraw(rows, color, projection2)
// Unique identifier
mesh.properties = feature.properties.name
province.add(line)
province.add(mesh)
})
})
}
if (feature.geometry.type === 'Polygon') {
/ / polygon
coordinates.forEach((coordinate) = > {
const mesh = drawExtrudeMesh(coordinate, color, projection2)
const line = lineDraw(coordinate, color, projection2)
// Unique identifier
mesh.properties = feature.properties.name
province.add(line)
province.add(mesh)
})
}
map2.add(province)
})
Enlarge / /
map2.scale.set(8.8.1)
scene2.add(map2)
}
Copy the code
- Only Chongqing is drawn here, the other provinces are drawn the same way.
- Modify the render function to load the new scene and see what it looks like.
// renderer.render(scene, camera)
renderer.render(scene2, camera)
Copy the code
Switching scenarios
- With the basics set up, we just need to modify the render function. Determine which province is the unique identifier in the function and switch to show that province.
/ / rendering
function render() {
// Display the province according to the unique identifier
if (lastPick && lastPick.object.properties === Chongqing Municipality) {
renderer.render(scene2, camera)
} else {
renderer.render(scene, camera)
}
requestAnimationFrame(render)
}
Copy the code
- The code address