If you don’t want to see the complicated steps, you can directly go to Github to download the project. If you can drop in a star haha

This project uses vue-CLI to create, but does not affect the use, the main drawing has been encapsulated into classes

1. Draw 3d maps using geoJson

1.1 Creation Scenarios
// Create a webGL renderer
this.renderer = new THREE.WebGLRenderer( { antialias: true.alpha: true});this.renderer.shadowMap.enabled = true; // Turn on shadows
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
this.renderer.toneMappingExposure = 1.25;   

// Adjust the color mode according to your needs
// this.renderer.outputEncoding = THREE.sRGBEncoding;  

this.renderer.outputEncoding = THREE.sHSVEncoding;
this.renderer.setPixelRatio( window.devicePixelRatio );
// Clear the background color, transparent background
this.renderer.setClearColor(0xffffff.0);
this.renderer.setSize(this.width, this.height);

/ / the scene
this.scene = new THREE.Scene();
this.scene.background = null
// Camera perspective camera
this.camera = new THREE.PerspectiveCamera(45.this.width / this.height, 0.1.5000);
this.camera.position.set(0, -40.70);
this.camera.lookAt(0.0.0);
Copy the code
1.2 Drawing a Map Based on JSON

Use Three. Shape to draw the plane edge data of the map, and then use Three. ExtrudeGeometry to pull up a surface into a 3D model. The same can be done for 3d pie chart

let jsonData = require('./json/china.json')
this.initMap(jsonData);

// the main part of the initMap method
initMap(chinaJson) {
    / *... Omit... * /
    chinaJson.features.forEach((elem, index) = > {
        // Specify a province 3D object
        const province = new THREE.Object3D();
        // Array of coordinates for each
        const { coordinates } = elem.geometry;
        const color = COLOR_ARR[index % COLOR_ARR.length]
        // Loop coordinate array
        coordinates.forEach(multiPolygon= > {
            
            multiPolygon.forEach((polygon) = > {
                const shape = new THREE.Shape();
                
                for (let i = 0; i < polygon.length; i++) {
                    let [x, y] = projection(polygon[i]);
                    
                    if (i === 0) {
                        shape.moveTo(x, -y);
                    }
                    shape.lineTo(x, -y);
                }
    
                const extrudeSettings = {
                    depth: 4.bevelEnabled: true.bevelSegments: 1.bevelThickness: 0.2
                };
    
                const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
               
                // Plane part material
                const material = new THREE.MeshStandardMaterial( {
                    metalness: 1.color: color,
                    
                } );
                // Raise some materials
                const material1 = new THREE.MeshStandardMaterial( {
                    metalness: 1.roughness: 1.color: color,
                    
                } );

                const mesh = new THREE.Mesh(geometry, [
                    material,
                    material1
                ]);
                // Set the height to distinguish the provinces
                if (index % 2= = =0) {
                    mesh.scale.set(1.1.1.2);
                }
                // Turn shadow on for mesh
                mesh.castShadow = true
                mesh.receiveShadow = truemesh._color = color province.add(mesh); }) }) _this.map.add(province); })}Copy the code

The coordinates of geoJson need to be transformed into plane coordinates by Mercator projection, and d3 is needed here

// Mercator projection conversion
const projection = d3.geoMercator().center([104.0.37.5]).scale(80).translate([0.0]);
Copy the code

2. Increase light

We have all kinds of light, ambient light, hemispherical light, point light, parallel light. Taking parallel light as an example, increase projection and adjust projection resolution to avoid Mosaic in projection

const light = new THREE.DirectionalLight( 0xffffff.0.5 ); 
light.position.set( 20, -50.20 );

light.castShadow = true;
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;

this.scene.add(light);
Copy the code

CastShadow = true: Enables projection

3. Add shadow blur

The default shadow has no blur effect and looks like an incandescent light without softness. Use CSM in the official example to increase shadow blur

import { CSM } from 'three/examples/jsm/csm/CSM.js';

this.csm = new CSM( {
    maxFar: params.far,
    cascades: 4.mode: params.mode,
    parent: this.scene,
    shadowMapSize: 1024.lightDirection: new THREE.Vector3( params.lightX, params.lightY, params.lightZ ).normalize(),
    camera: this.camera
} );
Copy the code

4. Add mouse events

In 3D space, mouse events mainly obtain the position of the mouse through rays. It can be imagined that the mouse emits a ray, and the first object it hits is the position of the mouse. The use of Threejs Raycaster, through the Raycaster to the corresponding provinces to increase the mouse in the highlighting effect and the province people suspension display effect

this.raycaster = new THREE.Raycaster();
// If the object group to be detected is passed in, all objects under the group will be detected. If it is irradiated, intersects has a value, indicating that the mouse is currently on these objects
const intersects = this.raycaster.intersectObject( this.group, true );
// Too much code to post, see GitHub source code
Copy the code

5, rendering

Threejs renders normally call the native requestAnimationFrame, and the main thing to do is call the Render method of the Renderer. Of course, since we did shadow blur, there’s more to do:

this.camera.updateMatrixWorld();
this.csm.update();
this.renderer.render(this.scene, this.camera);
Copy the code

6. Animation effects

If you have animations on the map, you can use tween.js, the Github address, for example, to animate the map annotations:

And finally, the project address