Frontend Development 9 min read

Using AMap Arrival Range API and Turf.js to Find Overlapping Commute Areas for Rental Decisions

This article demonstrates how to build a web page that leverages AMap's Arrival Range API and Turf.js to calculate reachable areas, compute their intersection, and search for residential communities within the overlap, providing a practical GIS solution for locating optimal rental locations.

Architecture Digest
Architecture Digest
Architecture Digest
Using AMap Arrival Range API and Turf.js to Find Overlapping Commute Areas for Rental Decisions

For GIS practitioners, an isochrone (or arrival range) represents the area reachable within a certain travel time using a specific mode of transportation. While traditional isochrones are often limited by real‑time traffic, AMap offers a more stable "bus and subway arrival range" API that works similarly but focuses on public transit.

The author created a simple web page with a control panel allowing users to select travel mode (subway + bus, subway only, or bus only) and a maximum travel time (up to 60 minutes). Clicking the map captures the latitude/longitude, resolves the address via reverse geocoding, and stores the point in currPositionList :

function handleMapClick(e: any) {
  if (!e.lnglat) return;
  if (currPositionList.value.length >= 2) {
    autolog.log("最多添加 2 个位置", 'error'); // you won't want three people sharing a house?
    return;
  }
  var lnglat = e.lnglat;
  geocoder.getAddress(lnglat, (status: string, result: { regeocode: any; info: string; }) => {
    if (status === "complete" && result.info === "OK") {
      currPositionList.value.push({ name: result.regeocode.formattedAddress, lnglat: [lnglat.lng, lnglat.lat] });
    }
  });
}

When the user clicks the "Query" button, the getArriveRange function iterates over the stored positions, calls the AMap Arrival Range service, and renders each polygon on the map:

function getArriveRange() {
  let loopCount = 0;
  for (let item of currPositionList.value) {
    arrivalRange.search(item.lnglat, currTime.value, (_status: any, result: { bounds: any; }) => {
      map.remove(polygons);
      if (!result.bounds) return;
      let currPolygons = [];
      loopCount++;
      for (let item of result.bounds) {
        let polygon = new AMap.Polygon(polygonStyle[`normal${loopCount}`] as "normal1" | "normal2");
        polygon.setPath(item);
        currPolygons.push(polygon);
      }
      map.add(currPolygons);
      polygons.push({ lnglat: item.lnglat, polygon: currPolygons, bounds: result.bounds });
      if (loopCount === currPositionList.value.length) {
        map.setFitView();
      }
    }, { policy: currStrategy.value });
  }
}

After both arrival ranges are obtained, the author uses turf.js to compute their geometric intersection. Because the API returns coordinate strings, a helper toNumber recursively converts all values to numbers before feeding them to Turf:

// Recursively convert string numbers in a multi‑dimensional array to actual numbers
function toNumber(arr: any) {
  return arr.map((item: any) => {
    if (Array.isArray(item)) {
      return toNumber(item);
    } else {
      return Number(item);
    }
  });
}

The intersection logic is added at the end of getArriveRange :

if (loopCount === currPositionList.value.length) {
  let poly1 = turf.multiPolygon(toNumber(polygons[0].bounds));
  let poly2 = turf.multiPolygon(toNumber(polygons[1].bounds));
  var intersection = turf.intersect(turf.featureCollection([poly1, poly2]));
  if (intersection) {
    let geojson = new AMap.GeoJSON({
      geoJSON: { type: "FeatureCollection", features: [intersection] },
      getPolygon: (_: any, lnglats: any) => {
        return new AMap.Polygon({ path: lnglats, ...polygonStyle.overlap });
      }
    });
    polygons.push({ lnglat: [0, 0], polygon: geojson, bounds: intersection.geometry.coordinates });
    map.add(geojson);
  } else {
    autolog.log("暂无交集,请自行查找", 'error');
  }
  map.setFitView();
}

The resulting map shows the two individual arrival polygons in different colors and the overlapping area in green, indicating locations where both parties can commute within the desired time.

To further assist the rental search, the author employs AMap.PlaceSearch to query residential communities ("小区") inside the intersected polygon:

placeSearch = new AMap.PlaceSearch({
  pageSize: 5, // results per page
  pageIndex: 1,
  map: map,
  autoFitView: true // auto‑adjust view to include all markers
});
placeSearch.searchInBounds('小区', intersection.geometry.coordinates);

Note that the searchInBounds request is a GET call, so very large polygons may exceed URL length limits.

In conclusion, the author highlights how a single map API can be extended with client‑side geometry processing to create useful, real‑world applications such as finding optimal rental locations based on combined commute ranges.

JavaScriptGISAMapArrivalRangeturf.jsWeb Mapping
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.