Some uses on projects based on Cesium native methods

When I first came to the company's project, I took over the code from a former colleague who left. Looking at other people's code is always an uncomfortable behavior. Open a new chapter and store some specifications and logic about Cesium in the project that "this design should be better". It is beyond the scope of this article to comment on the code specification of this personal preference.

1. Create a new dataset datasource to manage entity

1. How should we store the Entity object so that we can find it more conveniently

A former colleague, I like to use arrays most in projects. Each newly added Entity is stored in an array, and when it is cleared, the array is traversed and removed one by one.

var entityArr = [];        // 存储绘制的实体entity
function removeAllEntity(){
    entityArr.forEach(item){
        viewer.entities.remove(entity)
    }
}

When I first learned Cesium, I thought this was a good way. After all, the entity we want to remove on the map can be removed at any time. Later, when there was a requirement to aggregate entities on the map, I came into contact with Cesium's official data collection: new Cesium.DataSource()

And, in the official example, use: new Cesium.CustomDataSource(name) to complete an aggregation effect. What does this teach us? We can refer to the layer idea in PS, instead of drawing all entities in viewer.entities, we draw them in our own defined data set.

var selfDataSource = new Cesium.CustomDataSource('moduleName-whatUse');
viewer.dataSources.add(selfDataSource);
selfDataSource.entities.add({...option实体配置项});

First create a datasource, then add this collection to the viewer, and finally we only need to add to this collection to draw our entity.

What are the benefits of doing this? What scenarios can be applied to?

Frequent control is required when displaying, hiding and deleting certain entities. For example, the borderline of the national identity has been drawn on the map, and then when a certain province is clicked, the borderlines of other provinces are not required, and only the province selected by clicking is displayed. When returning to the national perspective, they need to be drawn again.

If you use an array to store these objects, you may need to traverse the array, and then set each entity as hidden or deleted.

But if these entities are all drawn on our own defined datasource, then we only need to control the display and hiding of this datasource.

var arr = [];        // 存了很多entity对象
var datasource = new Cesium.CustomDataSource(name);    // 自己定义的数据集合
viewer.dataSources.add(dataSource);

// 用数组去控制,删除/隐藏
arr.forEach(function (entity) {
    viewer.entities.remove(entity);    // 删除
    entity.show = false;        // 隐藏
})

// 数据集合来控制,删除/隐藏
datasource.show = false;        // 隐藏
datasource.entities.removeAll();    // 删除所有

In theory, we can create many datasets to manage our entities.

2. Use Cesium's own attributes to describe an entity 

 Each drawn entity can set its own id and name, but in work, an entity drawn based on a coordinate point only uses name and id to describe it, which is a bit too tasteless. Especially when it comes to click events.

Consider a demand situation like this:

After an icon on a map is clicked, some information about it needs to be displayed on the UI interface.

This is okay, after we use an ID to identify it, use the interface to request data, and then render and update the interface UI.

So what if the demand has changed like this?

After an icon on a map is clicked, it needs to display its category, parent category, and level of the coordinate point on the UI interface.

It's not difficult, isn't it just a matter of requesting more interfaces? However, when we request map coordinates through the interface, we already know some information about the coordinates. Are we going to make more use of this information?

It is: properties. One of the configuration items of Entity, this is not some visual graphics or anything, it is more used to describe this Entity.

let entity = viewer.entities.add({
    position,
    billboard,
    properties: {
        'name': Object对象
    }
})

Before talking about the use, let me talk about how my former colleague handles the click event of the entity.

Add map click event monitoring = "judgment whether the entity is clicked =" get the name or id of the entity, and then determine whether it contains a certain string = "corresponding click event.

When a former colleague drew an entity, he either gave the entity a special ID, or a string of names concatenated with an underscore. Many things are spliced ​​into strings with underscores and then assigned to name?

Ex-colleague's click event logic:

var handle = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handle.setInputAction(function(event) {
    var pick = viewer.scene.pick(event.position);
    if (Cesium.defined(pick) && (pick.id) && (pick.id._name)){    // 这里还同时判断有没有给name
        if(pick.id._name !== '某个字符串'){
            // 处理逻辑
            // 发起接口请求
        }else if(pick.id._name.indexOf('某个字符串') > -1){
            // 处理逻辑
            // 发起接口请求
        }
    }
},Cesium.ScreenSpaceEventType.LEFT_CLICK)

If we use properties to store when drawing, then we only need to do this.

let entity = viewer.entities.add({
    position,
    billboard,
    properties: {
        'name': Object对象,
        'address': Object对象
    }
})

handle.setInputAction(function(event) {
    var pick = viewer.scene.pick(event.position);
    if (Cesium.defined(pick) && (pick.id)){
        var ent = pick.id;
        if (ent.properties){    // 设置了properties属性
            if (ent.properties.hasProperty('name')) {         // 拥有name属性
                const name= entity.properties.name.getValue();
                const address= entity.properties.address.getValue();
                // 执行逻辑
            }
        }
    }
},Cesium.ScreenSpaceEventType.LEFT_CLICK)

What are the benefits? It's very simple, you use an underscore to read a string, and you need to know what the number means. I get the properties of this entity directly, and I know other information about this coordinate point.

When we request it through the interface and loop through the array to draw, we can store each sub-item in the corresponding entity. You can also control which ones are saved. Which method has more advantages and which method has better subsequent scalability can be seen at a glance.

3. Set the respective click event for the entity

Sometimes in the project, it is necessary to set some click events for the entities drawn on the map, and the general setting methods are similar. Get the scene of cesium, and then set up various listening events.

viewhandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
viewhandler.setInputAction(function (event){
    ....点击事件逻辑......
},Cesium.ScreenSpaceEventType.LEFT_CLICK)

When clicking, get the clicked entity entity, then get some information from the entity, and then execute the code. For entities with the same function, the code in the click event is relatively small and will not appear bloated. After all, they all use the same variable name to execute the same logic. What if there are three or four categories, or more than ten different execution logics? Constantly use if to judge or switch to execute different business logic?

If we set a click event for the entity, we only need to execute it when the logic is triggered. Wouldn't there be a lot less code in the click event? Of course, the logic of judging whether the entity is clicked is still necessary.

const entity = viewer.entities.add({
    name: '自己定义的entity名称',
    position: 坐标,
    label: {
        一些label的配置项
    }
})
entity.click = function() {
    console.log(this)        // 这会打印entity实体类的信息
    ...其他代码逻辑
    this.label.text = '点击之后更改的名称'
}

In the above code, we implemented a click event. When entity.click() is called, it will change the label text in the entity by itself. Then we judge in the registered click event.

viewhandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
viewhandler.setInputAction(function (event){
    ....点击事件逻辑......
    var pick = viewer.scene.pick(click.endPosition);
    if(pick && pick.id){
        const entity = pick.id;
        pick.click && pick.click();
    }
},Cesium.ScreenSpaceEventType.LEFT_CLICK)

In this way, we don't need to judge what kind of click event logic this entity will execute in the click event. And another advantage is that you can get the context at the time of creation. Creating entities is usually created in batches by traversing an array, so we can store the context of creating entities in the click event.

let context = this;
for(let index=0;index < 10;index++){
    const entity = viewer.entities.add({
        name: '自己定义的entity名称',
        position: 坐标,
        label: {
            一些label的配置项
        }
    })
    entity.click = function() {
        console.log(this)        // 这会打印entity实体类的信息
        console.log(index);
        console.log(context);
        ...其他代码逻辑
        this.label.text = '点击之后更改的名称'
        return {
            index,
            context
        }
    }
}

In this way, when we execute the entity, we can also return the execution context and know the value of the index. Although these two values ​​can be stored through the property attribute of the entity. . .

Setting the click event for the entity is mainly to achieve one: let the entity know what code logic to execute when it is clicked when it is created. This reduces the need to judge what to do based on attributes when being clicked. One active and one passive, each has its advantages and disadvantages.

Guess you like

Origin blog.csdn.net/GhostPaints/article/details/123459917