实现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);
});
}