Skip to content

Commit

Permalink
Merge pull request #438 from MapsPeople/feature/map-template-fit-boun…
Browse files Browse the repository at this point in the history
…ds-when-selecting-category

Map template: fit bounds when selecting category
  • Loading branch information
ammapspeople authored Jan 16, 2025
2 parents 21a4f0a + 9a56c69 commit 3fdb925
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
6 changes: 6 additions & 0 deletions packages/map-template/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.66.0] - 2025-01-16

## Added

- The map now fits to matching Locations when the user clicks/taps on a Category.

## [1.65.3] - 2025-01-15

## Fixed
Expand Down
51 changes: 48 additions & 3 deletions packages/map-template/src/components/Search/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function Search({ onSetSize, isOpen }) {
window.mapsindoors.services.LocationsService.getLocations({
categories: category,
venue: searchAllVenues ? undefined : venuesInSolution.find(venue => venue.name.toLowerCase() === currentVenueName.toLowerCase())?.name,
}).then(onResults);
}).then(results => onResults(results, true));
}

/**
Expand All @@ -136,15 +136,20 @@ function Search({ onSetSize, isOpen }) {
/**
* Handle search results from the search field.
*
* @param {array} locations
* @param {array} locations - An array of MapsIndoors Location objects.
* @param {boolean} fitMapBounds - If the map bounds should be adjusted to fit the locations.
*/
function onResults(locations) {
function onResults(locations, fitMapBounds = false) {
const displayResults = locations.slice(0, MAX_RESULTS);

setSearchResults(displayResults);
setFilteredLocations(displayResults);
setShowNotFoundMessage(displayResults.length === 0);

if (locations && fitMapBounds) {
fitMapBoundsToLocations(locations);
}

// Handles updates to scroll buttons when the category changes.
// When a category changes, the scroll buttons need to have their enabled/disabled states updated.
// Since some categories might load before the DOM element is fully rendered, we listen for the 'transitionend' event.
Expand All @@ -157,6 +162,46 @@ function Search({ onSetSize, isOpen }) {
}
}


/**
* Adjusts the map view to fit the bounds of the provided locations.
* It will filter out Locations that are not on the current floor or not part of the current venue.
*
* @param {Array} locations - An array of Location objects to fit within the map bounds.
*/
function fitMapBoundsToLocations(locations) {
if (!mapsIndoorsInstance.goTo) return; // Early exit to prevent crashes if using an older version of the MapsIndoors JS SDK. The goTo method was introduced in version 4.38.0.

const currentFloorIndex = mapsIndoorsInstance.getFloor();

// Create a GeoJSON FeatureCollection from the locations that can be used as input to the goTo method.
const featureCollection = {
type: 'FeatureCollection',
features: locations
// Filter out locations that are not on the current floor. If those were included, it could result in a wrong fit since they are not visible on the map anyway.
.filter(location => parseInt(location.properties.floor, 10) === parseInt(currentFloorIndex, 10))

// Filter out locations that are not part of the current venue. Including those when fitting to bounds could cause the map to zoom out too much.
.filter(location => location.properties.venueId.toLowerCase() === currentVenueName.toLowerCase())

// Map the locations to GeoJSON features.
.map(location => ({
type: 'Feature',
geometry: location.geometry,
properties: location.properties
}))
};

if (featureCollection.features.length > 0) {
Promise.all([getBottomPadding(), getLeftPadding()]).then(([bottomPadding, leftPadding]) => {
mapsIndoorsInstance.goTo(featureCollection, {
maxZoom: 22,
padding: { bottom: bottomPadding, left: leftPadding, top: 0, right: 0 }
});
});
}
}

/**
* Clear results list when search field is cleared.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/map-template/src/hooks/useMediaQuery.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useState, useEffect } from "react";
* @param {string} query
*/
const useMediaQuery = (query) => {
const [matches, setMatches] = useState(false);
const [matches, setMatches] = useState(window.matchMedia(query).matches);

useEffect(() => {
const media = window.matchMedia(query);
Expand Down

0 comments on commit 3fdb925

Please sign in to comment.