three.js SVG 学习绘制地图
https://www.js-css.cn/jscode/other/other43/
找到一个不错的资源,不过每个省份的svg数据太小了,不精确。
主要的是这个js文件:chinaMapConfig.js,有了它我们就可以根据svg路径绘制三维模型了。
这个网站也有svg的地图。http://mapsvg.com/maps/,相对精确一些,投影方式也不一样。
先测试一下内蒙古,没有问题。
var neimongol= transformSVGPathExposed(chinaMapConfig.shapes.neimongol);
var extrudeSettings = {
steps: 2,
depth: 16,
bevelEnabled: true,
bevelThickness: 1,
bevelSize: 1,
bevelSegments: 1
};
var geometry = new THREE.ExtrudeGeometry( neimongol, extrudeSettings );
var materiala = new THREE.MeshPhongMaterial( {
color: 0x00ffff ,
// wireframe:true
} );
var mesha = new THREE.Mesh( geometry, materiala ) ;
scene.add( mesha );
接着我们开始利用svg绘制完整的三维中国地图:
三维地图绘制完整,有点单调,添加一个交互事件。点击每个省份可以出发一个事件。
由于svg的坐标和three.js的坐标不一样,所以需要转换。
我新建了两个group,一个是把所有的省份添加进去,然后进行缩放平移操作。平移的依据是添加的box3,它计算出了group的包围盒。因为地图的本地坐标系不在中心,所以又添加了一个group是用来旋转操作。
最后使用Raycaster来检测点击的省份,并改变颜色,同时绘制了一个长方体。传参数group.children。只检测省份,默认是scene.children。
var group = new THREE.Group();
var chinaMap = new THREE.Group();
window.addEventListener( 'click', onDocumentMouseDown, false );
var extrudeSettings = {
steps: 2,
depth: 8,
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 1,
bevelSegments: 1
};
for (let shapesKey in chinaMapConfig.shapes) {
var materiala = new THREE.MeshPhongMaterial( {
color: 0xffffff*Math.random()
} );
var shapesvgs= $d3g.transformSVGPath(chinaMapConfig.shapes[shapesKey]);
var geometry = new THREE.ExtrudeGeometry( shapesvgs.toShapes(true), extrudeSettings );
var mesha = new THREE.Mesh( geometry, materiala ) ;
group.add( mesha );
}
group.scale.set(0.05,0.05,0.05);
var box = new THREE.Box3().expandByObject(group);
var bx = box.max.x-box.min.x,by = box.max.y-box.min.y,bz = box.max.z-box.min.z;
group.position.set(-bx/2,-by/2,-bz/2);
chinaMap.add(group);
chinaMap.rotation.x = Math.PI/2;
scene.add(chinaMap);
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(group.children);
if(intersects.length>0){
console.log(intersects[0].point);
intersects[0].object.material.color.set(0xff0000*Math.random());
cubeDr(4,intersects[0].point.x,intersects[0].point.y+4/2,intersects[0].point.z);
}
}
哦,上面忘记了介绍svg插件了。https://github.com/asutherland/d3-threeD。
这个插件也是7年没更新了,但是也不影响使用哈。
使用transformSVGPathExposed方法的时候需要引用下面的js插件。
<script src="../threejs/d3-three3D.js"></script>
两种常见的投影方式:
右侧的是叫墨卡托投影,是正轴等角圆柱投影。由荷兰地图学家墨卡托(G.Mercator)于1569年创立。假想一个与地轴方向一致的圆柱切或割于地球,按等角条件,将经纬网投影到圆柱面上,将圆柱面展为平面后,即得本投影。墨卡托投影在切圆柱投影与割圆柱投影中,最早也是最常用的是切圆柱投影。
左侧地图中台湾的左边又一条经度线,是倾斜的。但是在右边的图中,经度线就回成为垂直的。
上面的方法是使用svg的方法,有点局限性,一个是svg的地图难找,而且精确度难以把握,另一个原因是在地理数据可视化中,经纬度用不上。所以我们得改进一下,在我的另外一篇博客中介绍了使用geojson的方法绘制地图,这种方式的可操作行更好,值得学习。
Three.js之GeoJson 3D地图数据可视化飞行线实战
TMD离谱,文章内容违反国家相关法律法规了。 所以图片全部删了 ,换成你们看到的样子。