react-leaflet-deflate 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -35
- package/LICENSE +19 -19
- package/README.md +116 -89
- package/dist/react-leaflet-deflate.js +70 -85
- package/dist/react-leaflet-deflate.min.js +1 -1
- package/dist/react-leaflet-deflate.min.js.LICENSE.txt +9 -9
- package/docs/App.jsx +299 -299
- package/docs/css/business-frontpage.css +8 -8
- package/docs/geojsonSamples.js +149 -149
- package/docs/index.html +132 -132
- package/docs/vendor/bootstrap/css/bootstrap.css +9886 -9886
- package/docs/vendor/bootstrap/css/bootstrap.min.css +6 -6
- package/docs/vendor/bootstrap/js/bootstrap.bundle.js +6818 -6818
- package/docs/vendor/bootstrap/js/bootstrap.bundle.min.js +6 -6
- package/docs/vendor/bootstrap/js/bootstrap.js +4249 -4249
- package/docs/vendor/bootstrap/js/bootstrap.min.js +6 -6
- package/docs/vendor/jquery/jquery.js +10364 -10364
- package/docs/vendor/jquery/jquery.min.js +2 -2
- package/docs/vendor/jquery/jquery.slim.js +8269 -8269
- package/docs/vendor/jquery/jquery.slim.min.js +2 -2
- package/lib/Deflate.js +7 -7
- package/package.json +86 -87
- package/playwright.config.js +17 -0
- package/tests/e2e/deflate.spec.js +48 -0
- package/tests/e2e/empty-module.js +1 -0
- package/tests/e2e/fixture.jsx +120 -0
- package/tests/e2e/index.html +20 -0
- package/tests/e2e/server.js +42 -0
- package/webpack.e2e.config.js +23 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { defineConfig } = require('@playwright/test');
|
|
2
|
+
|
|
3
|
+
module.exports = defineConfig({
|
|
4
|
+
testDir: './tests/e2e',
|
|
5
|
+
testMatch: '**/*.spec.js',
|
|
6
|
+
use: {
|
|
7
|
+
baseURL: 'http://127.0.0.1:4173',
|
|
8
|
+
browserName: 'chromium',
|
|
9
|
+
headless: true,
|
|
10
|
+
},
|
|
11
|
+
webServer: {
|
|
12
|
+
command: 'npm run test:e2e:build && node tests/e2e/server.js',
|
|
13
|
+
url: 'http://127.0.0.1:4173',
|
|
14
|
+
reuseExistingServer: !process.env.CI,
|
|
15
|
+
timeout: 120000,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const { test, expect } = require('@playwright/test');
|
|
2
|
+
|
|
3
|
+
async function zoomTo12(page) {
|
|
4
|
+
const zoomOutput = page.getByTestId('zoom');
|
|
5
|
+
|
|
6
|
+
for (let zoom = 5; zoom <= 12; zoom += 1) {
|
|
7
|
+
await page.locator('.leaflet-control-zoom-in').click();
|
|
8
|
+
await expect(zoomOutput).toHaveText(String(zoom));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test.beforeEach(async ({ page }) => {
|
|
13
|
+
await page.goto('/');
|
|
14
|
+
await expect(page.getByRole('heading', { name: 'Deflate fixture' })).toBeVisible();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('deflates small features and opens their feature popup when zoomed in', async ({ page }) => {
|
|
18
|
+
await expect(page.locator('.leaflet-marker-icon')).toHaveCount(1);
|
|
19
|
+
await zoomTo12(page);
|
|
20
|
+
|
|
21
|
+
const features = page.locator('.leaflet-interactive');
|
|
22
|
+
await expect(features).toHaveCount(3);
|
|
23
|
+
await features.first().click();
|
|
24
|
+
await expect(page.locator('.leaflet-popup-content')).toContainText('Feature #1');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('toggles marker clustering on the map', async ({ page }) => {
|
|
28
|
+
const clusterCheckbox = page.getByRole('checkbox', { name: 'Marker clustering' });
|
|
29
|
+
await expect(clusterCheckbox).toBeChecked();
|
|
30
|
+
await expect(page.locator('.marker-cluster')).toBeVisible();
|
|
31
|
+
|
|
32
|
+
await clusterCheckbox.uncheck();
|
|
33
|
+
|
|
34
|
+
await expect(page.locator('.marker-cluster')).toHaveCount(0);
|
|
35
|
+
await expect(page.locator('.leaflet-marker-icon')).toHaveCount(3);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('applies minimum-size and data-set changes', async ({ page }) => {
|
|
39
|
+
await zoomTo12(page);
|
|
40
|
+
await expect(page.locator('.leaflet-interactive')).toHaveCount(3);
|
|
41
|
+
|
|
42
|
+
await page.getByRole('spinbutton', { name: 'Minimum size' }).fill('1000');
|
|
43
|
+
await expect(page.locator('.leaflet-marker-icon')).toHaveCount(3);
|
|
44
|
+
|
|
45
|
+
await page.getByRole('combobox', { name: 'GeoJSON data set' }).selectOption('2');
|
|
46
|
+
await expect(page.getByTestId('dataset')).toHaveText('Data set 2');
|
|
47
|
+
await expect(page.locator('.leaflet-marker-icon')).toHaveCount(1);
|
|
48
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { MapContainer, useMap } from 'react-leaflet';
|
|
4
|
+
import Deflate from '../../src';
|
|
5
|
+
|
|
6
|
+
const dataSets = {
|
|
7
|
+
1: {
|
|
8
|
+
type: 'FeatureCollection',
|
|
9
|
+
features: [
|
|
10
|
+
[-0.06, -0.02, 1],
|
|
11
|
+
[0, 0.02, 2],
|
|
12
|
+
[0.06, -0.02, 3],
|
|
13
|
+
].map(([longitude, latitude, id]) => ({
|
|
14
|
+
type: 'Feature',
|
|
15
|
+
properties: { id },
|
|
16
|
+
geometry: {
|
|
17
|
+
type: 'Polygon',
|
|
18
|
+
coordinates: [[
|
|
19
|
+
[longitude - 0.025, latitude - 0.025],
|
|
20
|
+
[longitude + 0.025, latitude - 0.025],
|
|
21
|
+
[longitude + 0.025, latitude + 0.025],
|
|
22
|
+
[longitude - 0.025, latitude + 0.025],
|
|
23
|
+
[longitude - 0.025, latitude - 0.025],
|
|
24
|
+
]],
|
|
25
|
+
},
|
|
26
|
+
})),
|
|
27
|
+
},
|
|
28
|
+
2: {
|
|
29
|
+
type: 'FeatureCollection',
|
|
30
|
+
features: [{
|
|
31
|
+
type: 'Feature',
|
|
32
|
+
properties: { id: 9 },
|
|
33
|
+
geometry: {
|
|
34
|
+
type: 'Polygon',
|
|
35
|
+
coordinates: [[
|
|
36
|
+
[0.01, 0.01],
|
|
37
|
+
[0.04, 0.01],
|
|
38
|
+
[0.04, 0.04],
|
|
39
|
+
[0.01, 0.04],
|
|
40
|
+
[0.01, 0.01],
|
|
41
|
+
]],
|
|
42
|
+
},
|
|
43
|
+
}],
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function ZoomReporter() {
|
|
48
|
+
const map = useMap();
|
|
49
|
+
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
const zoomOutput = document.querySelector('[data-testid="zoom"]');
|
|
52
|
+
const reportZoom = () => {
|
|
53
|
+
zoomOutput.textContent = String(map.getZoom());
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
map.on('zoomend', reportZoom);
|
|
57
|
+
reportZoom();
|
|
58
|
+
|
|
59
|
+
return () => map.off('zoomend', reportZoom);
|
|
60
|
+
}, [map]);
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function App() {
|
|
66
|
+
const [markerCluster, setMarkerCluster] = useState(true);
|
|
67
|
+
const [minSize, setMinSize] = useState(20);
|
|
68
|
+
const [dataSet, setDataSet] = useState('1');
|
|
69
|
+
|
|
70
|
+
return <>
|
|
71
|
+
<h1>Deflate fixture</h1>
|
|
72
|
+
<div className="controls">
|
|
73
|
+
<label>
|
|
74
|
+
<input
|
|
75
|
+
aria-label="Marker clustering"
|
|
76
|
+
type="checkbox"
|
|
77
|
+
checked={markerCluster}
|
|
78
|
+
onChange={(event) => setMarkerCluster(event.target.checked)}
|
|
79
|
+
/>
|
|
80
|
+
Marker clustering
|
|
81
|
+
</label>
|
|
82
|
+
<label>
|
|
83
|
+
Minimum size
|
|
84
|
+
<input
|
|
85
|
+
aria-label="Minimum size"
|
|
86
|
+
type="number"
|
|
87
|
+
value={minSize}
|
|
88
|
+
onChange={(event) => setMinSize(Number(event.target.value))}
|
|
89
|
+
/>
|
|
90
|
+
</label>
|
|
91
|
+
<label>
|
|
92
|
+
GeoJSON data set
|
|
93
|
+
<select
|
|
94
|
+
aria-label="GeoJSON data set"
|
|
95
|
+
value={dataSet}
|
|
96
|
+
onChange={(event) => setDataSet(event.target.value)}
|
|
97
|
+
>
|
|
98
|
+
<option value="1">Data set 1</option>
|
|
99
|
+
<option value="2">Data set 2</option>
|
|
100
|
+
</select>
|
|
101
|
+
</label>
|
|
102
|
+
</div>
|
|
103
|
+
<output data-testid="dataset">Data set {dataSet}</output>
|
|
104
|
+
<output data-testid="zoom">4</output>
|
|
105
|
+
<MapContainer center={[0, 0]} zoom={4} minZoom={1} maxZoom={22} className="map">
|
|
106
|
+
<ZoomReporter />
|
|
107
|
+
<Deflate
|
|
108
|
+
data={dataSets[dataSet]}
|
|
109
|
+
minSize={minSize}
|
|
110
|
+
markerCluster={markerCluster}
|
|
111
|
+
onEachFeature={(feature, layer) => {
|
|
112
|
+
layer.bindPopup(`Feature #${feature.properties.id}`);
|
|
113
|
+
layer.bindTooltip(`Feature #${feature.properties.id}`);
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
</MapContainer>
|
|
117
|
+
</>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>react-leaflet-deflate test fixture</title>
|
|
7
|
+
<link rel="stylesheet" href="/leaflet/leaflet.css">
|
|
8
|
+
<link rel="stylesheet" href="/markercluster/MarkerCluster.css">
|
|
9
|
+
<link rel="stylesheet" href="/markercluster/MarkerCluster.Default.css">
|
|
10
|
+
<style>
|
|
11
|
+
body { font-family: sans-serif; margin: 16px; }
|
|
12
|
+
.controls { display: flex; gap: 16px; margin-bottom: 12px; }
|
|
13
|
+
.map { height: 500px; width: 800px; }
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div id="root"></div>
|
|
18
|
+
<script src="/fixture.js"></script>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const root = path.resolve(__dirname, '../..');
|
|
6
|
+
const routes = {
|
|
7
|
+
'/': [path.join(__dirname, 'index.html'), 'text/html; charset=utf-8'],
|
|
8
|
+
'/debug.html': [path.join(root, 'example/debug.html'), 'text/html; charset=utf-8'],
|
|
9
|
+
'/src/Deflate.jsx': [path.join(root, 'src/Deflate.jsx'), 'text/javascript; charset=utf-8'],
|
|
10
|
+
'/debug/empty-module.js': [path.join(__dirname, 'empty-module.js'), 'text/javascript; charset=utf-8'],
|
|
11
|
+
'/fixture.js': [path.join(root, '.e2e-build', 'fixture.js'), 'text/javascript; charset=utf-8'],
|
|
12
|
+
'/leaflet/leaflet.css': [path.join(root, 'node_modules/leaflet/dist/leaflet.css'), 'text/css; charset=utf-8'],
|
|
13
|
+
'/markercluster/MarkerCluster.css': [path.join(root, 'node_modules/leaflet.markercluster/dist/MarkerCluster.css'), 'text/css; charset=utf-8'],
|
|
14
|
+
'/markercluster/MarkerCluster.Default.css': [path.join(root, 'node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css'), 'text/css; charset=utf-8'],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const server = http.createServer((request, response) => {
|
|
18
|
+
const pathname = new URL(request.url, 'http://127.0.0.1').pathname;
|
|
19
|
+
const imageMatch = pathname.match(/^\/leaflet\/images\/([A-Za-z0-9._-]+)$/);
|
|
20
|
+
const route = imageMatch
|
|
21
|
+
? [path.join(root, 'node_modules/leaflet/dist/images', imageMatch[1]), 'image/png']
|
|
22
|
+
: routes[pathname];
|
|
23
|
+
|
|
24
|
+
if (!route) {
|
|
25
|
+
response.writeHead(404);
|
|
26
|
+
response.end('Not found');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fs.readFile(route[0], (error, contents) => {
|
|
31
|
+
if (error) {
|
|
32
|
+
response.writeHead(500);
|
|
33
|
+
response.end(error.message);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
response.writeHead(200, { 'Content-Type': route[1] });
|
|
38
|
+
response.end(contents);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
server.listen(4173, '127.0.0.1');
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
mode: 'development',
|
|
5
|
+
entry: path.resolve(__dirname, 'tests/e2e/fixture.jsx'),
|
|
6
|
+
output: {
|
|
7
|
+
path: path.resolve(__dirname, '.e2e-build'),
|
|
8
|
+
filename: 'fixture.js',
|
|
9
|
+
clean: true,
|
|
10
|
+
},
|
|
11
|
+
module: {
|
|
12
|
+
rules: [
|
|
13
|
+
{
|
|
14
|
+
test: /\.(js|jsx)$/,
|
|
15
|
+
exclude: /node_modules/,
|
|
16
|
+
use: 'babel-loader',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
resolve: {
|
|
21
|
+
extensions: ['.js', '.jsx'],
|
|
22
|
+
},
|
|
23
|
+
};
|