banner
陈不易

陈不易

没有技术想聊生活
twitter
medium
tg_channel

Vector Tile Highlight Selection Openlayers[1]

In a small demo I created, there was a small requirement: to retrieve features with specified attributes through a database search and then highlight them.

If using the conventional WFS loading method, there is no problem; you can simply traverse the layer's feature source. There is no issue with the logic, regardless of efficiency. However, there is a requirement that the layer has a very large number of features (due to the buffer zones generated for coastlines on a global scale), so during the map loading process, vector tiles are used. The source of vector tiles does not have a getFeatures() method, which complicates the traversal of features that need to be highlighted.

The static style of the layer is set using the latest example from 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,
    })
  })
}

Here, selected is used for highlighting on mouse click. The logic is roughly that after clicking, the id of the feature is stored as a key value to indicate that the feature has been selected.

Naturally, when considering this requirement, my first thought was to traverse the featureCollection to find the corresponding Id of the relevant feature and store it in the global variable selection. However, since the vector tile source does not have a getFeatures() method, this idea fell through. I even considered creating a regular WFS layer to traverse the data, but the data volume was too large, requiring over 50 MB for a single load, making this approach completely unfeasible.

Later, considering that since 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 be effective and how the performance would be. Thus, after slight adjustments to the styleFunc, it became 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 parameter names is an array of country names, where the key of each item corresponds to the value that needs to be searched.

This method performs reasonably well with this data volume, as shown in the image below:

image

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