diff --git a/README.md b/README.md index 6a523c2..72a5a34 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ const Map = () => { ## Props -| Name | Type | Default | Description | -|------------|----------------------------------------------------------------------|--------------|------------------------------------| -| position? | [ControlOptions](https://leafletjs.com/reference.html#control-position) | "topleft" | The position of the control | -| title? | string | "Reset map view" | The control title. | -| icon? | string | "\u2610" | The control icon. Can be either a path for `url()` or a unicode character. | - - +| Name | Type | Default | Description | +|----------------|-------------------------------------------------------------------------|------------------|----------------------------------------------------------------------------| +| position? | [ControlOptions](https://leafletjs.com/reference.html#control-position) | "topleft" | The position of the control | +| title? | string | "Reset map view" | The control title. | +| icon? | string | "\u2610" | The control icon. Can be either a path for `url()` or a unicode character. | +| centerToReset? | [LatLng](https://leafletjs.com/reference.html#latlng) | undefined | Define a different center than the one mounted by the map | +| zoomToReset? | number | undefined | Define a different zoom than the one mounted by the map | diff --git a/__tests__/ResetViewControl.spec.tsx b/__tests__/ResetViewControl.spec.tsx index ed9295e..255ab1a 100644 --- a/__tests__/ResetViewControl.spec.tsx +++ b/__tests__/ResetViewControl.spec.tsx @@ -8,41 +8,76 @@ import { MapContainer, useMapEvents } from "react-leaflet"; import ResetViewControl from "../src/ResetViewControl"; import type { ResetViewControlOptions } from "../src/ResetViewControl"; +import { LatLng } from "leaflet"; +import type { Map } from "leaflet"; describe("ResetViewControl", () => { const mockHandleViewReset = jest.fn(); + let mapInstance = null as Map | null + const defaultMapCenter = new LatLng(-96.8716348, 32.8205866); + const defaultMapZoom = 5 - const ControlWrapper = ({ title, icon }: ResetViewControlOptions) => { + const ControlWrapper = ({ title, icon, centerToReset, zoomToReset }: ResetViewControlOptions) => { useMapEvents({ viewreset: mockHandleViewReset, }); return ( - <> - - + ); }; - const Map = ({ title, icon }: ResetViewControlOptions) => { + const Map = ({ title, icon, centerToReset, zoomToReset }: ResetViewControlOptions) => { return ( - - + mapInstance = map}> + ); }; test("can reset map view", () => { render(); + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter.lat, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter.lng, 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + + mapInstance?.setView(new LatLng(2, 46), 6) + + expect(mapInstance?.getCenter().lat).toBeCloseTo(2, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(46, 1); + expect(mapInstance?.getZoom()).toEqual(6) - userEvent.click(screen.getByTitle(/zoom out/i)); userEvent.click(screen.getByTitle("Reset view")); + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter.lat, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter.lng, 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + expect(mockHandleViewReset).toHaveBeenCalledTimes(2); }); + test("can reset the map view to a zoom and center different from those mounted by the map", () => { + const centerToReset = new LatLng(44.8, 6.3); + const zoomToReset = 17; + render(); + + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter.lat, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter.lng, 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + + userEvent.click(screen.getByTitle("Reset view")); + + expect(mapInstance?.getCenter().lat).toBeCloseTo(centerToReset.lat, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(centerToReset.lng, 1); + expect(mapInstance?.getZoom()).toEqual(zoomToReset) + + expect(mockHandleViewReset).toHaveBeenCalledTimes(3); + }); + test("can see icon", () => { render(); diff --git a/src/ResetViewControl.ts b/src/ResetViewControl.ts index 1748226..e1f41ca 100644 --- a/src/ResetViewControl.ts +++ b/src/ResetViewControl.ts @@ -1,7 +1,7 @@ import { createControlComponent } from "@react-leaflet/core"; import { Control, DomUtil, DomEvent, Util } from "leaflet"; -import type { Map, ControlOptions, LatLng } from "leaflet"; +import type { Map, ControlOptions, LatLng, LatLngExpression } from "leaflet"; export type ResetViewControlOptions = { /** @@ -14,15 +14,22 @@ export type ResetViewControlOptions = { * It renders a box by default. */ icon?: string; + + /** + * "zoomToReset" and "centerToReset" properties are useful when the map is mounted in a particular position + * and you need this button to reset the view to another position. + */ + zoomToReset?: number; + centerToReset?: LatLngExpression; } & ControlOptions; const _getControl = Control.extend({ - options: { position: "topleft", title: "Reset map view", icon: "\u2610" }, + options: { position: "topleft", title: "Reset map view", icon: "\u2610", zoomToReset: null, centerToReset: null }, onAdd: function (map: Map) { Util.setOptions(this, { - zoom: map.getZoom(), - center: map.getCenter(), + zoom: this.options.zoomToReset ?? map.getZoom(), + center: this.options.centerToReset ?? map.getCenter(), }); const { title, icon } = this.options;