Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty array queryRenderedFeatures on globe projection #5476

Open
Leningram opened this issue Feb 9, 2025 · 3 comments
Open

Empty array queryRenderedFeatures on globe projection #5476

Leningram opened this issue Feb 9, 2025 · 3 comments
Labels
need more info Further information is requested

Comments

@Leningram
Copy link

maplibre-gl-js version: 5.0.1

browser: Google Chrome

Steps to Trigger Behavior

  1. map.addSource('grid', {
    type: 'vector',
    tiles: [url],
    promoteId: 'gobject_id',
    maxzoom: 5,
    });

  2. map
    .addLayer({
    id: 'grid-layer',
    type: 'fill',
    source: 'grid',
    'source-layer': 'martin.test_function_mvt',
    paint: {
    'fill-color': [
    'case',
    ['boolean', ['feature-state', 'hover'], false],
    MapColors.objectHover,
    MapColors.object,
    ],
    'fill-opacity': 0.5,
    'fill-outline-color': '#000000',
    },
    })

  3. map.on('mousemove', 'grid-layer', (e) => {
    if (e.features && e.features.length > 0) {
    const feature = e.features.sort((a, b) => area(a) - area(b))[0];

     handleHover(feature);
     map.setFeatureState(
       { source: 'grid', sourceLayer: 'martin.test_function_mvt', id: feature.id },
       { hover: true }
     );
    

    }
    });

  4. function
    const handleHover = (feature: maplibregl.MapGeoJSONFeature) => {
    const features = map.current
    ?.queryRenderedFeatures({
    layers: ['grid-layer'],
    })
    ?.filter((item) => item.state.hover === true);
    // i removed the rest of logic of this function
    }

Expected Behavior Array features has items in globe projection as it has in standart projection.

Actual Behavior Array features always empty for globe projection, but contains items when projection is not 'globe'. Event if I remove filter by state.hover, it is always empty on globe.

@HarelM
Copy link
Collaborator

HarelM commented Feb 9, 2025

Can you please provide a jsbin with minimal reproduction?

@HarelM HarelM added the need more info Further information is requested label Feb 9, 2025
@Leningram
Copy link
Author

import { area } from '@turf/turf';
import maplibregl, { Map } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { useEffect, useMemo, useRef, useState } from 'react';
import { MapColors } from './config/constants';
import './map.css';
import { getRelief } from './testUtils';
import { TestProps } from './types';

const Maplibre = ({ gobjects, questions, isAdminBoundaries, isRussiaBoundaries, reliefId }: TestProps) => {
const mapContainer = useRef<HTMLDivElement | null>(null); // Правильный тип для контейнера карты
const map = useRef<Map | null>(null);
const [isLoading, setIsLoading] = useState(true); // Состояние для отслеживания загрузки карты
const hoveredFeatureIdRef = useRef<number | string | null>(null);

const Map = useMemo(() => {
return

;
}, [gobjects]);

const handleHover = (feature: maplibregl.MapGeoJSONFeature) => {
if (!map.current) {
return;
}
const features = map.current
?.queryRenderedFeatures({
layers: ['grid-layer'],
})
?.filter((item) => item.state.hover === true);
const featuresCircles = map.current
?.queryRenderedFeatures({
layers: ['circles-layer'],
})
?.filter((item) => item.state.hover === true);

[...features, ...featuresCircles].forEach((feature) => {
  map.current?.setFeatureState(
    { source: feature.source, id: feature.id, sourceLayer: feature.sourceLayer },
    { hover: false }
  );
});

map.current.getCanvas().style.cursor = 'pointer';
if (hoveredFeatureIdRef.current !== null && hoveredFeatureIdRef.current !== feature.id) {
  const sourceLayer = feature.source === 'markers-source' ? undefined : 'martin.test_function_mvt';
  map.current.setFeatureState(
    { source: feature.source, id: hoveredFeatureIdRef.current, sourceLayer },
    { hover: false }
  );
  map.current.setFeatureState({ source: 'markers-source', id: hoveredFeatureIdRef.current }, { hover: false });
}
if (feature.id || feature.properties?.id) {
  hoveredFeatureIdRef.current = feature.id || feature.properties.id;
}

};

const fetchObjects = async (map: Map) => {
const gobjectIds = gobjects
.filter(
(gobject) =>
!gobject.name.toLocaleLowerCase().includes('рек') && !gobject.name.toLocaleLowerCase().includes('канал')
)
.map((gobject) => gobject.id);
const riversIds = gobjects
.filter(
(gobject) =>
gobject.name.toLocaleLowerCase().includes('рек') || gobject.name.toLocaleLowerCase().includes('канал')
)
.map((gobject) => gobject.id);
const baseUrl = 'https://maptomind.ru/martin/martin.test_function_mvt/{z}/{x}/{y}?ids=';
const url = baseUrl + gobjectIds;
const riversUrl = baseUrl + riversIds;

if (isAdminBoundaries) {
  map.addSource('world_borders', {
    type: 'raster',
    tiles: [
      'https://maptomind.ru/geoserver/wms?service=WMS&request=GetMap&layers=world_borders&styles=&format=image/png&transparent=true&version=1.1.1&srs=EPSG:3857&bbox={bbox-epsg-3857}&width=256&height=256',
    ],
    tileSize: 256,
  });

  map.addLayer({
    id: 'world_borders',
    type: 'raster',
    source: 'world_borders',
    paint: {},
  });
}

if (isRussiaBoundaries) {
  map.addSource('russia', {
    type: 'raster',
    tiles: [
      'https://maptomind.ru/geoserver/wms?service=WMS&request=GetMap&layers=russia&styles=&format=image/png&transparent=true&version=1.1.1&srs=EPSG:3857&bbox={bbox-epsg-3857}&width=256&height=256',
    ],
    tileSize: 256,
  });

  map.addLayer({
    id: 'russia',
    type: 'raster',
    source: 'russia',
    paint: {},
  });
}

map.addSource('grid', {
  type: 'vector',
  tiles: [url],
  promoteId: 'gobject_id',
  maxzoom: 5,
});

map
  .addLayer({
    id: 'grid-layer',
    type: 'fill',
    source: 'grid',
    'source-layer': 'martin.test_function_mvt',
    paint: {
      'fill-color': [
        'case',
        ['boolean', ['feature-state', 'hover'], false],
        MapColors.objectHover,
        MapColors.object,
      ],
      'fill-opacity': 0.5,
      'fill-outline-color': '#000000',
    },
  })
  .on('idle', () => setIsLoading(false));

map.addSource('rivers', {
  type: 'vector',
  tiles: [riversUrl],
  promoteId: 'gobject_id',
  maxzoom: 4,
});

map
  .addLayer({
    id: 'rivers-layer',
    type: 'fill',
    source: 'rivers',
    'source-layer': 'martin.test_function_mvt',
    paint: {
      'fill-color': [
        'case',
        ['boolean', ['feature-state', 'hover'], false],
        MapColors.objectHover,
        MapColors.river,
      ],
      'fill-opacity': 0.5,
      'fill-outline-color': MapColors.river,
    },
  })
  .on('idle', () => setIsLoading(false));

map.on('mousemove', 'grid-layer', (e) => {
  if (window.innerWidth <= 768) {
    return;
  }
  if (e.features && e.features.length > 0) {
    const feature = e.features.sort((a, b) => area(a) - area(b))[0];
    handleHover(feature);
    map.setFeatureState(
      { source: 'grid', sourceLayer: 'martin.test_function_mvt', id: feature.id },
      { hover: true }
    );
  }
});

map.on('mouseleave', 'grid-layer', () => {
  if (window.innerWidth <= 768) {
    return;
  }
  if (hoveredFeatureIdRef.current !== null) {
    map.getCanvas().style.cursor = '';
    map.setFeatureState(
      { source: 'grid', sourceLayer: 'martin.test_function_mvt', id: hoveredFeatureIdRef.current },
      { hover: false }
    );
    hoveredFeatureIdRef.current = null;
  }
});

map.setPaintProperty('grid-layer', 'fill-color', [
  'case',
  ['boolean', ['feature-state', 'hover'], false],
  MapColors.objectHover,
  ['==', ['feature-state', 'correct'], 0],
  MapColors.wrong,
  ['==', ['feature-state', 'correct'], 1],
  MapColors.correct,
  ['==', ['feature-state', 'correct'], 2],
  MapColors.danger,
  ['==', ['feature-state', 'correct'], 3],
  MapColors.incorrect,
  ['==', ['feature-state', 'correct'], 4],
  MapColors.wrong,
  ['==', ['feature-state', 'correct'], 5],
  MapColors.hint,
  MapColors.object,
]);

};

useEffect(() => {
if (map.current || !mapContainer.current) return;
map.current = new maplibregl.Map({
container: mapContainer.current!,
transformRequest: (url_) => {
return {
url: url_,
headers: {},
};
},
style: getRelief(reliefId),
center: [0, 0],
zoom: 2,
}).addControl(new maplibregl.GlobeControl(), 'bottom-right');

map.current.addControl(new maplibregl.NavigationControl({ visualizePitch: true }), 'bottom-right');

map.current.on('load', async () => {
  fetchObjects(map.current!);
});

}, [gobjects]);

return (
<>

{Map}

</>
);
};

export default Maplibre;

@HarelM
Copy link
Collaborator

HarelM commented Feb 11, 2025

This is not helpful in the current state, please provide a jsbin instead of trying to copy the code here...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
need more info Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants