This is the third day of my participation in Gwen Challenge.

preface

I happened to see this effect in a video, and then I gradually clarified my thoughts and started to realize it. Simply speaking, it is realized by using Entity’s display and hiding and coordinate transformation. Because it’s a wild path, the implementation might be a little rough or redundant, so let’s start.

The basic idea

We need to use the click event to obtain the selected entity, hide the current entity and obtain its peripheral coordinate set to generate a new polygon, and enlarge and translate this polygon. We also need to provide a close button to exit the so-called hierarchical mode.

How do we manipulate a coordinate set so that the polygons it represents can be scaled or shifted? This is to use our geographical analysis library, Turf.js. For the introduction of Turf and its basic use, I have covered Turf in Turf.js – Enabling you to implement geographical analysis on your browser.

How do you implement the close button? Remember from the previous article that we did a simple text tag class encapsulation, the same idea is to render the specified div element into a Cesium container, and specify the required logic, methods, etc.

implementation

Layered effect

With a clear mind, we can start implementing features. Similarly, we can implement functions first and then encapsulate them. In this article, we only post the key code, and you can implement it yourself after reading the article.

First we must load an entity, which is a cliche I won’t go into here, and then we need to register a click event that triggers a function that responds to clicking on the entity.

let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction((movement) = > {
    let pick = viewer.scene.pick(movement.position);
    if (Cesium.defined(pick)) {
        if(! pick.id.isFloor) {this.showFloor(pick.id);
        } else {
            this.selectFloor(pick.id);
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
Copy the code

In the response function we first hide the clicked entity to make room for our hierarchical entity set. Then we get the peripheral coordinate set of this entity and use it as the coordinate set of our hierarchical entity.

showFloor(entity) {
    viewer.entities.getById(entity.id).show = false;
    let height = 30;
    for (let i = 0; i < entity.floor; i++) {
        let floor = {
            name: "floor" + i,
            id: entity.id + "F" + i,
            isFloor: true.floor: i + 1.positions: entity.positions,
            polygon: {
                // hierarchy: Cesium.Cartesian3.fromDegreesArray(floorPos),
                hierarchy: entity.polygon.hierarchy._value,
                material: Cesium.Color.YELLOW.withAlpha(0.4),
                height,
                outline: true.ouelineColor: Cesium.Color.BLACK,
            },
        };
        height += 60; viewer.entities.add(floor); }},Copy the code

So we have our basic layering.

Select the effect

Next we implement the selected effect, the selected effect we can use highlighting, pan, zoom and their combination to show, highlighting is not described here, the effect in our grid implementation that article has been implemented, this paper mainly to achieve the zoom effect.

To achieve this effect we need to use Turf.js for coordinate transformation, so we first install Turf in the project

npm i @turf/turf
Copy the code

We need to use the Polygon and transformScale implementations in Turf.js. For convenience, WHEN the Entity was initially generated, I bound its 2d coordinate group to the Entity as an attribute for subsequent use. In the actual project according to the specific situation of the adjustment, such as the use of THREE-DIMENSIONAL coordinate transformation or according to the entity ID retrieval interface acquisition.

If we want to use Turf, we have to follow its format. So first we need to generate a Turf-recognized Polygon entity, then zoom it in or out and get its enlarged coordinate array.

let poly = turf.polygon([positions]);
let translatedPoly = turf.transformScale(poly, 1.4);
let transPoints = translatedPoly.geometry.coordinates[0];
Copy the code

Then generate an entity and add it to the entity set.

This is just the most basic implementation. If you think about it completely, you will find that there is still a lot to improve. For example: click the selected floor after unselected, selected floor uniqueness and so on.

Complete method:

selectFloor(floor) {
    console.log(floor);
    let positions = floor.positions;
    let poly, translatedPoly, transPoints, floorPosSingle = [];
    poly = turf.polygon([positions]);
    translatedPoly = turf.transformScale(poly, 1.4);
    transPoints = translatedPoly.geometry.coordinates[0];
    transPoints.forEach((item) = > {
        floorPosSingle.push(item[0], item[1]);
    });

    let selectFloor = {
        name: "select_floor".id: 'active_' + floor.id,
        isFloor: true.isActive: true.polygon: {
            hierarchy: Cesium.Cartesian3.fromDegreesArray(floorPosSingle),
            material: Cesium.Color.RED.withAlpha(0.4),
            height: floor.polygon.height._value,
            outline: true.outlineColor: Cesium.Color.BLACK,
        },
    };

    viewer.entities.getById(floor.id).show = false
    viewer.entities.add(selectFloor)
},
Copy the code

Close button

The close button is not explained too much here. It is similar to the idea of dynamic text markup, except that the DOM is now bound with a click event that triggers the deletion of the hierarchical entity set and the restoration of the display floor. How to call a method in a vue file in a wrapped class

/ / class class
this._vmInstance.closeEvent = e= > {
    this.close();
};

close() {
    this._vmInstance.show = false; / / remove the dom
    / / do something...
}
Copy the code
<div :id="id" class="close-container" v-if="show" @click="closeClick"></div> closeClick() {if (this.closeEvent) { this.closeEvent(); }},Copy the code

A special case

Sometimes we find that our entity is not a complete polygon, but a ring or a polygon with a hole, and we get crazy errors using this method. The reason is that in both Ceisum and Turf, the coordinate format of polygons with holes is different from that of regular polygons. Here is a brief description of how polygons with holes are generated in the two libraries.

Cesium

In Ceisum, entity.polygon. Hierarchy, as the peripheral coordinate set of polygons, provides two notation. The notation above is abbreviated and does not have holes by default, while polygons with holes need to provide an object containing two fields, positions and holes. As the name implies, one is the peripheral coordinate set and one is the hole coordinate set. Holes can provide multiple coordinate sets, equivalent to digging multiple holes.

let entity = {
    polygon: {hierarchy: {positions: Cesium.Cartesian3.fromDegreesArray(outPos),
            holes: [{positions: Cesium.Cartesian3.fromDegreesArray(inPos) }
            ]
        }
    }
}
Copy the code
Turf.js

However, in Turf, we cannot cut the hole directly, we can only save the country by curving, generating polygons for the coordinate set of the hole and the peripheral coordinate set and amplifying them respectively. After obtaining the coordinate set, we can achieve the desired implementation.

The last

This example combines the previous encapsulated DOM class with the use of click events. It is a rough but useful example to reinforce our knowledge. This article will also be included in my column, which also has other effects, interested partners can click to subscribe. If you have good suggestions or reminders, please browse in the comments section or add contact information to learn and progress together.