如何编写考虑缩放、特征状态和数据驱动样式的 Mapbox 绘制表达式?

How to write a Mapbox paint expression that accounts for zoom, feature-state, and data-driven styling?

我有一个层将 geojson 源中的点要素呈现为圆圈。这是其中一项功能的示例:

{
  type: 'Feature',
  properties: {
    color: 'red',
    red: true,
    green: false
  },
  geometry: {
    type: 'Point',
    coordinates: [-77.038659, 38.931567]
  }
};

我希望 circle-opacity 是 3 个因素的产物(要素的某些属性、地图缩放以及要素状态中用于确定是否应隐藏该要素的布尔值)。我想不出一种方法来编写一个能解释所有这三个问题的表达式。缩放规则的限制似乎是问题所在。

这是我要编写的逻辑:

if (feature-state.hidden) {
    opacity = 0;
} else if (properties.red) {
    opacity = 1;
} else if (properties.green and zoom >= 10) {
    opacity = 1;
} else if (zoom >= 15) {
    opacity = 1;
} else {
    opacity = 0;
}

我试过这样写一个不透明表达式:

'circle-opacity': [
  'case',
  ['to-boolean', ['feature-state', 'hidden']], 0,
  ['to-boolean', ['get', 'red']], 1,
  ['to-boolean', ['get', 'green']], ['case', ['>=', ['zoom'], 10], 1, 0], // I could also write a permutation of this using an ['all'] rule
  ['>=', ['zoom'], 15], 1,
  0,
],

此消息被拒绝:"Error: layers.places.paint.circle-opacity: "zoom" expression may only be used as input to a top-level "step" or "interpolate" expression."

然后我尝试了这样的事情:

'circle-opacity': [
  'step',
  ['zoom'],
  0,
  [
    'case',
    ['to-boolean', ['get', 'red'], false], 1,
    ['to-boolean', ['get', 'green'], false], 10,
    15
  ],
  1
]

此消息被拒绝:“错误:layers.places.paint.circle-opacity[3]:"step" 表达式的 Input/output 对必须使用文字数值(不是计算表达式)定义) 作为输入值。"

如您所见,我什至还没有开始添加功能状态检查。

这是一个可以玩的 JSFiddle:https://jsfiddle.net/rognstad/px4c8tbe/17/

我想我可以通过使用 minZoom 属性 将每种颜色分解成它自己的图层然后只对特征状态使用不透明度表达式来使其工作,但这感觉真的很笨拙并且会导致性能更差。

看来必须有更好的方法。对于如何实现这一目标,您有更好的建议吗?谢谢!

你真的很接近。您收到此错误:

Error: layers.places.paint.circle-opacity[3]: Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.

因为您的 ['step'] 表达式中参数的顺序有点不对。它需要去:

['step', ['zoom'], <value at zoom 0>, <X>, <value at zoom X>, <Y>, <value at zoom Y>

所以你不想先 0 那里。

如果我们稍微重构一下您的伪代码,您应该可以做到:

step
  zoom
  // zoom 0 to 10
  if (!feature-state.hidden && properties.red) {
    1
  } else {
    0
  }
  10 // zoom level 10+
  if (!feature-state.hidden && (properties.red || properties.green) {
    1
  } else {
    0
  }
  15 // zoom level 15+
  if (!feature-state.hidden) {
    1
  } else {
    0
  }

表达式代码看起来像这样。您可能必须添加适当的类型转换。 (我没有测试过)。

['step', ['zoom'],
['case', ['all', ['!', ['feature-state', 'hidden']], ['get', 'red'], 1, 0],
10,
['case', ['all', ['!', ['feature-state', 'hidden']], ['any', ['get', 'red'], ['get', 'green']], 1, 0],
15,
['case', [['!', ['feature-state', 'hidden']], 1, 0]],