Skip to content
目录

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

This document is generated by mdpress