banner
陈不易

陈不易

没有技术想聊生活
twitter
medium
tg_channel

Vector tile highlight selected Openlayers[1]

title: "Highlighting Selected Vector Tiles in Openlayers[1]"
date: 2019-12-16T18:29:06+08:00
draft: false
tags: ["javascript","openlayers"]
categories: ["map"]#

In my own small demo, there is a small requirement: retrieve features with specified attributes from a database and then highlight them.

If we load the features using the conventional WFS method, there is no problem. We can simply iterate through the feature source of the layer. However, there is a requirement that the layer has a large number of features (because it is a buffer zone generated from the global coastline), so we use vector tiles during the map loading process. The vector tile type source does not have a "getFeatures()" method, which makes it difficult to iterate through the features that need to be highlighted.

The static style of the layer is set using the latest example of "openlayers":

// Color table
const colorTable = {
  "No": "rgba(200, 54, 54, 0)",
  "type1": "#FF0000",
  "type2": "#E69800",
  ...
  "": "#00FFFFFF",
};
export function createRiskLevelStyle(feature) {

  const riskLevel = feature.get('props_X');
  let selected = !!selection[feature.getId()];
  return new Style({
    fill: new Fill({
      //color: colorTable[riskLevel],
      color: selected ? 'rgba(200,20,20,0.8)' : colorTable[riskLevel],
      //color: 
    }),
    stroke: new Stroke({
      color: '#FFFFFF',
      width: 0.1,
    })
  })
}

The "selected" variable is used for highlighting when the mouse is clicked. The logic is that after clicking, the feature's ID is stored as the key in the "selection" global variable to indicate that the feature is selected.

Naturally, when considering this requirement, my first thought was to iterate through the "featureCollection" to find the corresponding feature's ID and store it in the "selection" global variable. However, this idea failed because the vector tile source does not have a "getFeatures()" method. Later, I even thought about creating a new regular WFS layer to iterate through the data, but the data volume was too large, and loading it once would require over 50MB, so this approach also failed completely.

Afterwards, considering that the style can be set using this form of "styleFunc" during loading, I wondered if assigning a new "Func" to the layer during retrieval would work and how the performance would be. So I made some adjustments to the "styleFunc" as follows:

export function createRiskLevelStyleSearch(names) {
  return function (feature) {
    const riskLevel = feature.get('props_X');
    let properties = feature.getProperties();
    let zh = properties['label'];
    let en = properties['name'];
    let searched = false;
    if (zh === undefined || en === undefined) {
      searched = false;
    } else {
      names.forEach((v) => {
        if (en === v.key)
          searched = true;
      });
    }
    return new Style({
      fill: new Fill({
        //color: colorTable[riskLevel],
        color: searched ? 'rgba(200,20,20,0.8)' : colorTable[riskLevel],
        //color:
      }),
      stroke: new Stroke({
        color: '#FFFFFF',
        width: 0.1,
      })
    });
  }

}

The "names" parameter is an array of country names, and the "key" of each "item" corresponds to the value to be searched.

This method works reasonably well with this data volume, as shown in the following image:

image

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.