实现3D的行政区效果
准备数据
从 datav 地图小工具 这里下载对应的行政区的geojson数据,自己的项目里的数据从哪里下载还是自己生产的有你的项目决定,这里我只是测试使用,故从datav 地图小工具下载了香港的数据
WARNING
地图数据是个很敏感的东西,尤其是国家的行政边界,项目里使用请遵循对应的法律政策,我这里只是测试使用
创建相关的图层
这里我使用了three插件来实现了3D行政区了,你也可以使用ExtrudePolygonLayer图层
js
// the ThreeLayer to draw buildings
var threeLayer = new maptalks.ThreeLayer('t', {
identifyCountOnEvent: 1,
animation: true
// forceRenderOnMoving: true,
// forceRenderOnRotating: true
});
threeLayer.prepareToDraw = function (gl, scene, camera) {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, -10, 10).normalize();
scene.add(light);
scene.add(new THREE.AmbientLight('#fff', 0.3));
addPolygons();
};
// threeLayer.addTo(map);
// 添加到GroupGLLayer中
// GroupGLLayer能实现抗锯齿等后处理,也能加入其他三维图层,让子图层都融合到同一个三维空间中
const sceneConfig = {
postProcess: {
enable: true,
antialias: { enable: true }
}
};
const groupLayer = new maptalks.GroupGLLayer('group', [threeLayer], { sceneConfig });
groupLayer.addTo(map);
加载数据并构造3D的行政区
- 关于每个图形的配色,使用了colorin 这个颜色插值库,其也是maptalks里默认使用的颜色插值库
- 把图形的海拔高度设置为负的目的是不要抬高海平面,方便其他的业务图层数据加到地图,否则会要求其他图层也要设置海拔数据,导致业务逻辑变复杂了,这个样子最简单和不容易出错
js
const colors = [
[2000, 'lightskyblue'],
[12000, 'yellow'],
[30000, 'orangered']
];
const ci = new colorin.ColorIn(colors);
function addPolygons() {
fetch('../assets/data/hk.json').then(res => res.json()).then(geojson => {
const polygons = maptalks.GeoJSON.toGeometry(geojson);
const extrudePolygons = polygons.map(p => {
const { value } = p.getProperties();
const [r, g, b] = ci.getColor(value);
const color = `rgb(${r},${g},${b})`;
const extrudePolygon = threeLayer.toExtrudePolygon(p, { height, altitude: -height, topColor: '#fff' }, new THREE.MeshPhongMaterial({ color }));
return extrudePolygon;
});
threeLayer.addMesh(extrudePolygons);
})
}
添加高亮效果
高亮效果即鼠标移动上去,对图形高亮提示,使该图形成为显眼包
,这里我们添加图形的mouseover
,mouseout
事件处理函数,在对应的事件里更新图形的样式即可
- mouseover 高亮图形
- mouseout 还原图形原始的样式
js
const highMaterial = new THREE.MeshPhongMaterial({ color: '#fff', vertexColors: 2 });
function mouseEventFunc(e) {
const polygon = e.target;
if (e.type === 'mouseover') {
if (!polygon._oldSymbol) {
polygon._oldSymbol = polygon.getObject3d().material;
}
polygon.getObject3d().material = highMaterial;
} else if (e.type === 'mouseout') {
if (polygon._oldSymbol) {
polygon.getObject3d().material = polygon._oldSymbol;
}
}
}
function addPolygons() {
fetch('../assets/data/hk.json').then(res => res.json()).then(geojson => {
const polygons = maptalks.GeoJSON.toGeometry(geojson);
const extrudePolygons = polygons.map(p => {
const { value } = p.getProperties();
const [r, g, b] = ci.getColor(value);
const color = `rgb(${r},${g},${b})`;
const extrudePolygon = threeLayer.toExtrudePolygon(p, { height, altitude: -height, topColor: '#fff' }, new THREE.MeshPhongMaterial({ color }));
extrudePolygon.on('mouseover mouseout', mouseEventFunc);
return extrudePolygon;
});
threeLayer.addMesh(extrudePolygons);
})
}
添加边框线和文字标注
- 边框线还是使用了图形
Polygon
,只是把其填充的透明度设置为0而已 - 文字标注即用点图形,用文字样式系统而已
- 开启文字碰撞
js
const layer = new maptalks.VectorLayer('layer', {
// enableAltitude: true
geometryEvents: false,
'collision': true,
'collisionDelay': 250
}).addTo(map);
function addOutLines(polygons) {
polygons.forEach(polygon => {
polygon.setSymbol({
polygonOpacity: 0,
lineWidth: 0.6,
lineColor: '#444',
});
});
layer.addGeometry(polygons);
}
function addLabels() {
fetch('../assets/data/hklabel.geojson').then(res => res.json()).then(geojson => {
const points = maptalks.GeoJSON.toGeometry(geojson);
points.forEach(point => {
const { name } = point.getProperties();
point.setSymbol({
textName: name,
textHaloRadius: 0.2,
textHaloFill: '#fff'
});
});
layer.addGeometry(points);
})
}