From eb66c26519712fabbfbeca3eaef5177396d5d3ae Mon Sep 17 00:00:00 2001 From: Florian Sommariva <1926041+dtrucs@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:07:33 +0100 Subject: [PATCH 1/3] Define better lng/lat/zoom tests --- __tests__/ResetViewControl.spec.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/__tests__/ResetViewControl.spec.tsx b/__tests__/ResetViewControl.spec.tsx index ed9295e..2669d6d 100644 --- a/__tests__/ResetViewControl.spec.tsx +++ b/__tests__/ResetViewControl.spec.tsx @@ -8,9 +8,13 @@ import { MapContainer, useMapEvents } from "react-leaflet"; import ResetViewControl from "../src/ResetViewControl"; import type { ResetViewControlOptions } from "../src/ResetViewControl"; +import type { LatLngExpression, Map } from "leaflet"; describe("ResetViewControl", () => { const mockHandleViewReset = jest.fn(); + let mapInstance = null as Map | null + const defaultMapCenter = [-96.8716348, 32.8205866] as LatLngExpression; + const defaultMapZoom = 5 const ControlWrapper = ({ title, icon }: ResetViewControlOptions) => { useMapEvents({ @@ -28,7 +32,7 @@ describe("ResetViewControl", () => { }; const Map = ({ title, icon }: ResetViewControlOptions) => { return ( - + mapInstance = map}> ); @@ -36,10 +40,22 @@ describe("ResetViewControl", () => { test("can reset map view", () => { render(); + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter[0], 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + + mapInstance?.setView([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[0], 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + expect(mockHandleViewReset).toHaveBeenCalledTimes(2); }); From cf0a459ca4c0436d27907eb86498e20a42bdf303 Mon Sep 17 00:00:00 2001 From: Florian Sommariva <1926041+dtrucs@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:13:34 +0100 Subject: [PATCH 2/3] Define the new optional properties "centerToReset" and "centerToZoom" --- README.md | 14 +++++------ __tests__/ResetViewControl.spec.tsx | 36 +++++++++++++++++++++-------- src/ResetViewControl.ts | 15 ++++++++---- 3 files changed, 45 insertions(+), 20 deletions(-) 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 2669d6d..5a7f42d 100644 --- a/__tests__/ResetViewControl.spec.tsx +++ b/__tests__/ResetViewControl.spec.tsx @@ -16,24 +16,24 @@ describe("ResetViewControl", () => { const defaultMapCenter = [-96.8716348, 32.8205866] as LatLngExpression; 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}> - + ); }; @@ -59,6 +59,24 @@ describe("ResetViewControl", () => { expect(mockHandleViewReset).toHaveBeenCalledTimes(2); }); + test("can reset the map view to a zoom and center different from those mounted by the map", () => { + const centerToReset = [44.8, 6.3] as LatLngExpression; + const zoomToReset = 17; + render(); + + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter[0], 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) + + userEvent.click(screen.getByTitle("Reset view")); + + expect(mapInstance?.getCenter().lat).toBeCloseTo(centerToReset[0], 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(centerToReset[1], 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; From 8cfb1bcdca52332776681147db0006eb70a34278 Mon Sep 17 00:00:00 2001 From: Florian Sommariva <1926041+dtrucs@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:58:51 +0100 Subject: [PATCH 3/3] Use new LatLng leaflet function to define map center on unit test --- __tests__/ResetViewControl.spec.tsx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/__tests__/ResetViewControl.spec.tsx b/__tests__/ResetViewControl.spec.tsx index 5a7f42d..255ab1a 100644 --- a/__tests__/ResetViewControl.spec.tsx +++ b/__tests__/ResetViewControl.spec.tsx @@ -8,12 +8,13 @@ import { MapContainer, useMapEvents } from "react-leaflet"; import ResetViewControl from "../src/ResetViewControl"; import type { ResetViewControlOptions } from "../src/ResetViewControl"; -import type { LatLngExpression, Map } from "leaflet"; +import { LatLng } from "leaflet"; +import type { Map } from "leaflet"; describe("ResetViewControl", () => { const mockHandleViewReset = jest.fn(); let mapInstance = null as Map | null - const defaultMapCenter = [-96.8716348, 32.8205866] as LatLngExpression; + const defaultMapCenter = new LatLng(-96.8716348, 32.8205866); const defaultMapZoom = 5 const ControlWrapper = ({ title, icon, centerToReset, zoomToReset }: ResetViewControlOptions) => { @@ -40,11 +41,11 @@ describe("ResetViewControl", () => { test("can reset map view", () => { render(); - expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter[0], 1); - expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter.lat, 1); + expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter.lng, 1); expect(mapInstance?.getZoom()).toEqual(defaultMapZoom) - mapInstance?.setView([2, 46], 6) + mapInstance?.setView(new LatLng(2, 46), 6) expect(mapInstance?.getCenter().lat).toBeCloseTo(2, 1); expect(mapInstance?.getCenter().lng).toBeCloseTo(46, 1); @@ -52,26 +53,26 @@ describe("ResetViewControl", () => { userEvent.click(screen.getByTitle("Reset view")); - expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter[0], 1); - expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + 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 = [44.8, 6.3] as LatLngExpression; + const centerToReset = new LatLng(44.8, 6.3); const zoomToReset = 17; render(); - expect(mapInstance?.getCenter().lat).toBeCloseTo(defaultMapCenter[0], 1); - expect(mapInstance?.getCenter().lng).toBeCloseTo(defaultMapCenter[1], 1); + 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[0], 1); - expect(mapInstance?.getCenter().lng).toBeCloseTo(centerToReset[1], 1); + 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);