我想在将鼠标悬停在填充挤出功能上时突出显示它们。 与此相关的样式使用表达式和功能状态是直接的,但我在检索正确的功能时遇到了困难。
网上有代码可以在鼠标悬停时更改功能状态,而且看起来很简单,所以我对其进行了修改:
var hover_id = null;
const feature_state = { hover: true }
map.on('mousemove', '3d-buildings', (e) => {
// Get features under cursor, following render order
const features = map.queryRenderedFeatures(e.point);
// Check that features are not empty
if (features.length > 0) {
// Clean up previously hovered feature
if (hover_id) {
map.removeFeatureState({source: "composite", sourceLayer: 'building', id: hover_id});
}
// Set feature state of the new hovered feature
hover_id = features[0].id;
map.setFeatureState({source: 'composite', sourceLayer: 'building', id: hover_id}, feature_state);
console.log(hover_id)
}
});
虽然最初效果很好,但一旦我使用鼠标右键倾斜相机,它就会停止工作。倾斜后,最前面的元素不再被选择(似乎选择了其他元素并打印出 ID,但地图上没有显示任何内容,也不会引发错误)。 与此相关的是,只有在放大相当远的距离后才会选择正确的功能 - 在很大的缩放范围内,建筑物已经渲染到屏幕上,但似乎没有被 queryRenderedFeatures 拾取。这是预期的行为吗?
预期行为: map.queryRenderedFeatures(...)[0] 选择最重要的特征,与相机倾斜无关。
相机倾斜影响特征选择的可能原因是什么?这是一个错误还是我滥用了 API?
我认为您面临的问题与倾斜无关,而是与您添加和删除状态而不是更改状态值这一事实有关。状态必须在图层定义中声明,用表达式改变颜色,然后只需要改变状态的值即可。
这里有一个我创建的小提琴来展示如何在鼠标悬停/移出时更改填充挤压的颜色
相关代码是这样的:
let mapConfig = {
NYC: {
origin: [-74.044514, 40.689259, 39],
center: [-74.0137, 40.70346, 0],
zoom: 16.2,
pitch: 60,
bearing: 35
}
}
mapboxgl.accessToken = 'PUT YOUR TOKEN HERE';
let point = mapConfig.NYC;
var map = new mapboxgl.Map({
style: 'mapbox://styles/mapbox/streets-v11',
center: point.center,
zoom: point.zoom,
pitch: point.pitch,
bearing: point.bearing,
container: 'map',
antialias: true,
hash: true
});
map.on('style.load', function() {
if (map.getSource('composite')) {
map.addLayer({
'id': '3d-buildings',
'source': 'composite',
'source-layer': 'building',
'type': 'fill-extrusion',
'minzoom': 14,
'paint': {
'fill-extrusion-color': [
'case',
['boolean', ['feature-state', 'hover'], false],
'#ff0000',
'#ddd'
],
'fill-extrusion-height': ["number", ["get", "height"], 5],
'fill-extrusion-base': ["number", ["get", "min_height"], 0],
'fill-extrusion-opacity': 1
}
}, 'road-label');
}
let fHover;
map.on('mousemove', function(e) {
//157001066
var features = map.queryRenderedFeatures(e.point, {
layers: ['3d-buildings']
});
if (features[0]) {
mouseout();
mouseover(features[0]);
} else {
mouseout();
}
});
map.on('mouseout', function(e) {
mouseout();
});
function mouseout() {
if (!fHover) return;
map.getCanvasContainer().style.cursor = 'default';
map.setFeatureState({
source: fHover.source,
sourceLayer: fHover.sourceLayer,
id: fHover.id
}, {
hover: false
});
}
function mouseover(feature) {
fHover = feature;
map.getCanvasContainer().style.cursor = 'pointer';
map.setFeatureState({
source: fHover.source,
sourceLayer: fHover.sourceLayer,
id: fHover.id
}, {
hover: true
});
}
});
如果此答案解决了您的问题,请将其标记为接受答案,这样也将帮助其他用户知道这是正确的解决方案。
@jscastro 这工作得很好:我的要求是我需要用纬度和经度改变一些建筑物的颜色。我已经通过使用下面的 API 实现了从纬度和经度获取建筑物 ID
我在这里面临一个问题,颜色仅在缩放级别 17 后才发生变化。我想更改缩放级别 15 上的颜色。
map.on("style.load", function () {
if (map.getSource("composite")) {
const layers = map.getStyle().layers;
const labelLayerId = layers.find(
(layer) => layer.type === "symbol" && layer.layout["text-field"]
).id;
map.addLayer(
{
id: "3d-buildings",
source: "composite",
"source-layer": "building",
filter: ["==", "extrude", "true"],
type: "fill-extrusion",
minzoom: 15,
zoom: 15,
pitch: 60,
bearing: -60,
layout: {
// Make the layer visible by default.
visibility: "visible",
},
paint: {
"fill-extrusion-color": [
"case",
["boolean", ["feature-state", "hover"], false],
"#00ff00",
"#AED0EC",
],
"fill-extrusion-height": [
"interpolate",
["linear"],
["zoom"],
15,
0,
15.5,
["get", "height"],
],
"fill-extrusion-base": [
"interpolate",
["linear"],
["zoom"],
15,
0,
15.05,
["get", "min_height"],
],
"fill-extrusion-opacity": 1,
},
},
labelLayerId
);
}
map.getCanvasContainer().style.cursor = "pointer";
map.setFeatureState(
{
source: "composite",
sourceLayer: "building",
id: "4411722601841895",
},
{
hover: true,
}
);
map.getCanvasContainer().style.cursor = "pointer";
map.setFeatureState(
{
source: "composite",
sourceLayer: "building",
id: "1315660041727095",
},
{
hover: true,
}
);
map.getCanvasContainer().style.cursor = "pointer";
map.setFeatureState(
{
source: "composite",
minzoom: 15,
sourceLayer: "building",
id: "3957345234349675",
},
{
hover: true,
}
);
map.getCanvasContainer().style.cursor = "pointer";
map.setFeatureState(
{
source: "composite",
sourceLayer: "building",
id: "5328485811",
},
{
hover: true,
}
);
});