Skip to content
目录

楼层动画

要求:

  • 楼层数据的展示
  • 楼层动画,当选中一个楼层时:
    • 如果楼层没有展开,那么高于这个楼层的要自动展开
    • 如果楼层已经展开了,那么当前楼层和小于该楼层的要自动闭合

floor-animation demo

楼层效果

E%7B(KGSEI485EBBYF2%606P5IU.png

这个没有要多说的,不同的楼层设置图形为不同的海拔即可,这里我使用的threelayer,直接贴代码了

WARNING

为了方便做楼层悬浮动画,我把楼层的原始海拔值用_altitude记录,这个值不会随着更新图形的海拔值而改变的,如果直接用图形的 altitude因为这个值随动画不断的变化,在使用起来比较复杂,容易出错

因为同一个楼层房间的边框线一般不用交互纯展示效果,我们可以使用toLines来批量展示,这样可以有更好的性能的

js
function addFloors(buildingGeoJSON, roomGeoJSON) {
    const floorGeoJSON = buildingGeoJSON.features[0];
    let baseObjects = [];
    for (let i = 1; i <= floorCount; i++) {
        const altitude = (i - 1) * floorHeight;
        const floor = threeLayer.toExtrudePolygon(
            floorGeoJSON,
            {
                height: 0.5,
                topColor: "#fff",
                altitude,
                _altitude: altitude, //原始的海拔
            },
            material,
        );
        baseObjects.push(floor);

        const rooms = roomGeoJSON.features.map((f) => {
            return threeLayer.toExtrudePolygon(
                f,
                {
                    height: roomHeight,
                    topColor: "#fff",
                    altitude,
                    _altitude: altitude,
                },
                material1,
            );
        });
        baseObjects = baseObjects.concat(rooms);

        const lines = roomGeoJSON.features.map((f) => {
            return new maptalks.LineString(f.geometry.coordinates[0]);
        });
        const border = threeLayer.toLines(
            lines,
            {
                topColor: "#fff",
                altitude: altitude + roomHeight,
                _altitude: altitude + roomHeight,
            },
            borderMaterial,
        );
        baseObjects.push(border);

        floorCache[i] = {
            floorNum: i,
            open: false,
            floors: [floor],
            altitude,
            rooms,
            borders: [border],
        };
    }
    threeLayer.addMesh(baseObjects);
}

楼层悬浮状态判断

  • 楼层动画,当选中一个楼层时:

    • 如果楼层没有展开,那么高于这个楼层的要自动展开
    • 如果楼层已经展开了,那么当前楼层和小于该楼层的要自动闭合
  • 楼层状态数据了我们添加open字段来记录当前楼层的展开状态,当选中一个楼层时根据这个状态值来判断楼层时需要展开还是闭合

  • 楼层究竟是展开还是闭合和快关一样,open=true/false而已

  • 楼层从展开->闭合时其自身也要加入更新海拔的数据列表中

js
function selectChange(e) {
    const selectFloor = parseInt(e.target.value);
    const floorItem = floorCache[selectFloor];
    if (!floorItem) {
        return;
    }
    const open = floorItem.open;
    const isDown = open;
    const needsUpdateFloors = [];
    if (isDown) {
        floorItem.open = false;
        needsUpdateFloors.push(floorItem);
    }
    for (const key in floorCache) {
        const floorItem = floorCache[key];
        const { floorNum, open } = floorItem;
        if (isDown) {
            //小于选中楼层并且是打开状态
            if (floorNum < selectFloor && open) {
                needsUpdateFloors.push(floorItem);
                floorItem.open = false;
            }
        } else {
            //大于选中楼层并且是关闭状态
            if (floorNum > selectFloor && !open) {
                needsUpdateFloors.push(floorItem);
                floorItem.open = true;
            }
        }
    }

    const allMeshes = getAllMeshes(needsUpdateFloors);

    allMeshes.forEach((mesh) => {
        //记录当前图形的实时海拔
        mesh.options._altitude = mesh.options.altitude;
    });

    animationFloor(allMeshes, isDown);
}

楼层这个动画

这里直接使用maptalks自带的animate()函数即可,关于animate()的使用,请参阅 高级/动画章节

js
function animationFloor(allMeshes, isDown) {
    if (player) {
        player.finish();
    }
    const update = (alitutde) => {
        allMeshes.forEach((mesh) => {
            const _altitude = mesh.options._altitude;
            mesh.setAltitude(_altitude + alitutde);
        });
    };
    var targetStyles = {
        symbol: {
            alitutde: offsetHeight,
        },
    };

    // animate by maptalks.animation.Animation
    player = maptalks.animate(
        targetStyles,
        {
            duration: 1000,
            easing: "out",
            repeat: false,
        },
        // callback of each frame
        function step(frame) {
            let alitutde = frame.symbol.alitutde;
            if (isDown) {
                alitutde = -alitutde;
            }
            update(alitutde);
        },
    );
    player.play();
}

maptalks教程 document auto generated by mdpress and vitepress