Skip to content

Commit

Permalink
Added support for lat-lng objects (#164)
Browse files Browse the repository at this point in the history
* Add initial unit testing

* Added support for latlng objects and initial Controls tests
  • Loading branch information
halocline authored Aug 20, 2024
1 parent 55ff110 commit 0c3d269
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 12 deletions.
19 changes: 17 additions & 2 deletions grommet-leaflet/src/layers/Controls/Controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ export const LocationBounds = ({ locations }) => {
location.geometry?.coordinates[1],
]);
});
} else {
} else if (Array.isArray(locations[0])) {
locations.forEach(location => {
bounds.extend([location?.[0], location?.[1]]);
});
} else {
locations.forEach(location => {
bounds.extend([location?.lat, location?.lng]);
});
}

return bounds;
Expand Down Expand Up @@ -95,7 +99,18 @@ const Controls = ({ locations }) => {
};

Controls.propTypes = {
locations: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
locations: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.number),
PropTypes.shape({
lat: PropTypes.number,
lng: PropTypes.number,
}),
]),
),
PropTypes.object,
]),
};

export { Controls };
133 changes: 128 additions & 5 deletions grommet-leaflet/src/layers/Controls/Controls.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,79 @@
import React from "react";
import { expect, test } from "vitest";
import { render } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import { Grommet } from 'grommet';
import { Map } from '../Map/index.js';
import { Controls } from './index.js';
import { Grommet } from "grommet-icons";

const TILE_LAYER = {
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
}

const LAT_LNG_PAIRS = [
[0, 0],
[10, -10],
[-10, -10],
[5, -8],
[2, 2],
[-5, 5],
[39.397, -100.644],
[39.897, -104.644]
];

const GEO_JSON = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [10, -10]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-10, -10]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [5, -8]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [2, 2]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-5, 5]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [39.397, -100.644]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [39.897, -104.644]
}
}]
};

const LAT_LNG_OBJECTS = LAT_LNG_PAIRS.map(([lat, lng]) => ({ lat, lng }))

test('Controls renders', async () => {
render(
<Grommet>
Expand All @@ -17,5 +82,63 @@ test('Controls renders', async () => {
</Map>
</Grommet>
);
expect(1 + 1).toBe(2);
});

const zoomIn = screen.getByRole('button', { name: /zoom in/i });
const zoomOut = screen.getByRole('button', { name: /zoom out/i });
expect(zoomIn).toBeTruthy();
expect(zoomOut).toBeTruthy();
});

test('displays zoom to data control', async () => {
render(
<Grommet>
<Map tileLayer={TILE_LAYER}>
<Controls locations={[[-34.397, 150.644]]} />
</Map>
</Grommet>
);

const zoomToData = screen.getByRole('button', { name: /zoom to data/i });
expect(zoomToData).toBeTruthy();
});

test('locations accepts array of lat/lng pairs', async () => {
render(
<Grommet>
<Map tileLayer={TILE_LAYER}>
<Controls locations={LAT_LNG_PAIRS} />
</Map>
</Grommet>
);

const zoomToData = screen.getByRole('button', { name: /zoom to data/i });
expect(zoomToData).toBeTruthy();
});

test('locations accepts array of lat/lng objects', async () => {
render(
<Grommet>
<Map tileLayer={TILE_LAYER}>
<Controls locations={LAT_LNG_OBJECTS} />
</Map>
</Grommet>
);

const zoomToData = screen.getByRole('button', { name: /zoom to data/i });
expect(zoomToData).toBeTruthy();
});

test('locations accepts GeoJSON', async () => {
render(
<Grommet>
<Map tileLayer={TILE_LAYER}>
<Controls locations={GEO_JSON} />
</Map>
</Grommet>
);

const zoomToData = screen.getByRole('button', { name: /zoom to data/i });
expect(zoomToData).toBeTruthy();
});

// ToDo: Add test for zooming to data
2 changes: 1 addition & 1 deletion grommet-leaflet/src/layers/Controls/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import * as L from 'leaflet';

export interface ControlsProps {
locations?: L.LatLngExpression[];
locations?: L.LatLngExpression[] | number[][] | GeoJSON;
}

declare const Controls: React.FC<ControlsProps>;
Expand Down
7 changes: 7 additions & 0 deletions grommet-leaflet/src/layers/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from './Cluster';
export * from './Controls';
export * from './Map';
export * from './Marker';
export * from './MarkerCluster';
export * from './Pin';
export * from './Popup';
8 changes: 4 additions & 4 deletions grommet-leaflet/src/layers/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from './Cluster';
export * from './Controls/Controls';
export * from './Controls';
export * from './Map';
export * from './Marker/Marker';
export * from './Marker';
export * from './MarkerCluster';
export * from './Pin/Pin';
export * from './Popup/Popup';
export * from './Pin';
export * from './Popup';

0 comments on commit 0c3d269

Please sign in to comment.