├── .eslintrc
├── .github
├── FUNDING.yml
└── workflows
│ └── publish.yml
├── .gitignore
├── API.md
├── CHANGELOG.md
├── LICENCE
├── README.md
├── dist
├── maplibre-gl-compare.css
└── maplibre-gl-compare.js
├── example
├── index.html
└── index.js
├── index.js
├── package-lock.json
├── package.json
├── style.css
└── test
└── index.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "browser": true
5 | },
6 | "globals": {
7 | "maplibregl": true
8 | },
9 | "rules": {
10 | "strict": [0],
11 | "curly": [0],
12 | "no-new": [0],
13 | "no-alert": [0],
14 | "no-extra-bind": [0],
15 | "no-redeclare": [1],
16 | "new-cap": [0],
17 | "eol-last": [0],
18 | "no-mixed-requires": [0],
19 | "no-path-concat": [0],
20 | "camelcase": [0],
21 | "consistent-return": [0],
22 | "no-underscore-dangle": [0],
23 | "comma-spacing": [0],
24 | "key-spacing": [0],
25 | "no-use-before-define": [0]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [maplibre]
2 | open_collective: maplibre
3 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: publish
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | tags:
7 | - v*
8 |
9 | jobs:
10 | publish:
11 | name: Publish
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Use Node.js 10 x64
17 | uses: actions/setup-node@v2
18 | with:
19 | node-version: 10
20 | architecture: x64
21 | registry-url: 'https://registry.npmjs.org'
22 |
23 | - name: Publish
24 | run: |
25 | npm publish --access=public --non-interactive
26 | env:
27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_ORG_TOKEN }}
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | example/style.css
3 | .idea/
4 |
--------------------------------------------------------------------------------
/API.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ### Table of Contents
4 |
5 | * [Compare][1]
6 | * [Parameters][2]
7 | * [Examples][3]
8 | * [setSlider][4]
9 | * [Parameters][5]
10 | * [on][6]
11 | * [Parameters][7]
12 | * [fire][8]
13 | * [Parameters][9]
14 | * [off][10]
15 | * [Parameters][11]
16 |
17 | ## Compare
18 |
19 | * **See**: [Swipe between maps][12]
20 |
21 | ### Parameters
22 |
23 | * `a` **[Object][13]** The first MapLibre GL Map
24 | * `b` **[Object][13]** The second MapLibre GL Map
25 | * `container` **([string][14] | [HTMLElement][15])** An HTML Element, or an element selector string for the compare container. It should be a wrapper around the two map Elements.
26 | * `options` **[Object][13]**
27 |
28 | * `options.orientation` **[string][14]** The orientation of the compare slider. `vertical` creates a vertical slider bar to compare one map on the left (map A) with another map on the right (map B). `horizontal` creates a horizontal slider bar to compare on mop on the top (map A) and another map on the bottom (map B). (optional, default `vertical`)
29 | * `options.mousemove` **[boolean][16]** If `true` the compare slider will move with the cursor, otherwise the slider will need to be dragged to move. (optional, default `false`)
30 |
31 | ### Examples
32 |
33 | ```javascript
34 | var compare = new maplibregl.Compare(beforeMap, afterMap, '#wrapper', {
35 | orientation: 'vertical',
36 | mousemove: true
37 | });
38 | ```
39 |
40 | ### setSlider
41 |
42 | Set the position of the slider.
43 |
44 | #### Parameters
45 |
46 | * `x` **[number][17]** Slider position in pixels from left/top.
47 |
48 | ### on
49 |
50 | Adds a listener for events of a specified type.
51 |
52 | #### Parameters
53 |
54 | * `type` **[string][14]** The event type to listen for; one of `slideend`.
55 | * `fn`
56 | * `listener` **[Function][18]** The function to be called when the event is fired.
57 |
58 | Returns **[Compare][19]** `this`
59 |
60 | ### fire
61 |
62 | Fire an event of a specified type.
63 |
64 | #### Parameters
65 |
66 | * `type` **[string][14]** The event type to fire; one of `slideend`.
67 | * `data` **[Object][13]** Data passed to the event listener.
68 |
69 | Returns **[Compare][19]** `this`
70 |
71 | ### off
72 |
73 | Removes an event listener previously added with `Compare#on`.
74 |
75 | #### Parameters
76 |
77 | * `type` **[string][14]** The event type previously used to install the listener.
78 | * `fn`
79 | * `listener` **[Function][18]** The function previously installed as a listener.
80 |
81 | Returns **[Compare][19]** `this`
82 |
83 | [1]: #compare
84 |
85 | [2]: #parameters
86 |
87 | [3]: #examples
88 |
89 | [4]: #setslider
90 |
91 | [5]: #parameters-1
92 |
93 | [6]: #on
94 |
95 | [7]: #parameters-2
96 |
97 | [8]: #fire
98 |
99 | [9]: #parameters-3
100 |
101 | [10]: #off
102 |
103 | [11]: #parameters-4
104 |
105 | [12]: https://maplibre.org/maplibre-gl-js-docs/plugins/
106 |
107 | [13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
108 |
109 | [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
110 |
111 | [15]: https://developer.mozilla.org/docs/Web/HTML/Element
112 |
113 | [16]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
114 |
115 | [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
116 |
117 | [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
118 |
119 | [19]: #compare
120 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com/)
5 | and this project adheres to [Semantic Versioning](http://semver.org/).
6 |
7 | ## [Unreleased]
8 |
9 | ### Added
10 |
11 | - Forked from https://github.com/mapbox/mapbox-gl-compare
12 |
13 | ### Changed
14 |
15 | - Changed the text mapboxgl to maplibregl
16 |
17 | ### Deprecated
18 |
19 | ### Removed
20 |
21 | ### Fixed
22 |
23 | ### Security
24 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 MapLibre contributors
2 |
3 | Copyright (c) 2016, Mapbox
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## MapLibre GL Compare
2 |
3 | Swipe and sync between two MapLibre maps. This plugin was originally developed for Mapbox (https://github.com/mapbox/mapbox-gl-compare) and was migrated to MapLibre after Mapbox changed its license.
4 |
5 | ## Code example
6 |
7 | ### Examples
8 |
9 | #### Full Example without the need of a token
10 |
11 | ```js
12 |
13 |
14 |
15 |
16 | Swipe between maps
17 |
21 |
22 |
23 |
27 |
40 |
41 |
42 |
43 |
63 |
64 |
65 |
69 |
93 |
94 |
95 | ```
96 |
97 | #### Full Example with the need of a token
98 |
99 | ```js
100 |
101 |
102 |
103 |
104 | Swipe between maps
105 |
109 |
110 |
111 |
115 |
128 |
129 |
130 |
131 |
151 |
152 |
153 |
157 |
182 |
183 |
184 | ```
185 |
186 | ### Usage
187 |
188 | ```js
189 | var beforeMap = new maplibregl.Map({
190 | container: "before",
191 | style: "https://demotiles.maplibre.org/style.json",
192 | center: [7.221275, 50.326111],
193 | zoom: 5,
194 | });
195 |
196 | var afterMap = new maplibregl.Map({
197 | container: "after",
198 | style:
199 | "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/style.json",
200 | center: [7.221275, 50.326111],
201 | zoom: 5,
202 | });
203 |
204 | // A selector or reference to HTML element
205 | var container = '#comparison-container';
206 |
207 | var map = new maplibregl.Compare(beforeMap, afterMap, container, {
208 | mousemove: true, // Optional. Set to true to enable swiping during cursor movement.
209 | orientation: 'vertical' // Optional. Sets the orientation of swiper to horizontal or vertical, defaults to vertical
210 | });
211 | ```
212 |
213 | ### Methods
214 |
215 | ```js
216 | compare = new maplibregl.Compare(beforeMap, afterMap, container, {
217 | mousemove: true, // Optional. Set to true to enable swiping during cursor movement.
218 | orientation: 'vertical' // Optional. Sets the orientation of swiper to horizontal or vertical, defaults to vertical
219 | });
220 |
221 | // Get Current position - this will return the slider's current position, in pixels
222 | compare.currentPosition;
223 |
224 | // Set Position - this will set the slider at the specified (x) number of pixels from the left-edge or top-edge of viewport based on swiper orientation
225 | compare.setSlider(x);
226 |
227 | //Listen to slider movement - and return current position on each slideend
228 | compare.on('slideend', (e) => {
229 | console.log(e.currentPosition);
230 | });
231 |
232 | //Remove - this will remove the compare control from the DOM and stop synchronizing the two maps.
233 | compare.remove();
234 | ```
235 |
236 | ## Live examples
237 |
238 | [Compare hybrid with streets](https://rawcdn.githack.com/astridx/astridx.github.io/a9d7297a4fe1e3a4d7ebeb1e4e662fd1339ef3b5/maplibreexamples/plugins/maplibre-gl-compare-swipe-between-maps.html)
239 |
240 | [Compare swisstopo with demotiles](https://rawcdn.githack.com/astridx/astridx.github.io/a9d7297a4fe1e3a4d7ebeb1e4e662fd1339ef3b5/maplibreexamples/plugins/maplibre-gl-compare-swipe-between-maps_.html)
241 |
242 | ## Installation
243 |
244 | ### Native
245 |
246 | Add tags referencing `maplibre-gl-compare` after adding `maplibre-gl` to your website:
247 |
248 | ```html
249 |
250 |
251 |
252 |
253 |
254 |
255 | ```
256 |
257 | ### Node
258 |
259 |
260 |
261 | ## Motivation
262 |
263 | This project makes it possible to easily compare two maps.
264 |
265 | ## API Reference
266 |
267 | [API Reference](API.md)
268 |
269 | ## Bug Reports & Feature Requests
270 |
271 | Please use the [issue tracker](https://github.com/maplibre/maplibre-gl-compare/issues) to report any bugs or file feature requests.
272 |
273 | ## Licence
274 | ISC © [MapLibre](https://github.com/maplibre) © [Mapbox](https://github.com/mapbox)
275 |
--------------------------------------------------------------------------------
/dist/maplibre-gl-compare.css:
--------------------------------------------------------------------------------
1 | .maplibregl-compare {
2 | background-color: #fff;
3 | position: absolute;
4 | width: 2px;
5 | height: 100%;
6 | z-index: 1;
7 | }
8 | .maplibregl-compare .compare-swiper-vertical {
9 | background-color: #3887be;
10 | box-shadow: inset 0 0 0 2px #fff;
11 | display: inline-block;
12 | border-radius: 50%;
13 | position: absolute;
14 | width: 60px;
15 | height: 60px;
16 | top: 50%;
17 | left: -30px;
18 | margin: -30px 1px 0;
19 | color: #fff;
20 | cursor: ew-resize;
21 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjYwIiAgIGhlaWdodD0iNjAiICAgdmVyc2lvbj0iMS4xIiAgIHZpZXdCb3g9IjAgMCA2MCA2MCIgICBpZD0ic3ZnNTQzNCIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxK2RldmVsK29zeG1lbnUgcjEyOTExIiAgIHNvZGlwb2RpOmRvY25hbWU9Imwtci5zdmciPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE1NDQ0Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzNTQ0MiIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4NiIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlkPSJuYW1lZHZpZXc1NDQwIiAgICAgc2hvd2dyaWQ9InRydWUiICAgICBpbmtzY2FwZTp6b29tPSI0IiAgICAgaW5rc2NhcGU6Y3g9IjI1Ljg4OTgzMSIgICAgIGlua3NjYXBlOmN5PSIzNC4zODE4MzMiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIgICAgIGlua3NjYXBlOndpbmRvdy15PSIyMyIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc1NDM0IiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIiAgICAgaW5rc2NhcGU6c25hcC1zbW9vdGgtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkNTk4OSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPHBhdGggICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAgICAgZD0iTSAyNSAyNCBMIDE2IDMwIEwgMjUgMzYgTCAyNSAyNCB6IE0gMzUgMjQgTCAzNSAzNiBMIDQ0IDMwIEwgMzUgMjQgeiAiICAgICBpZD0icGF0aDU5OTUiIC8+PC9zdmc+);
22 | }
23 |
24 | .maplibregl-compare-horizontal {
25 | position: relative;
26 | width: 100%;
27 | height: 2px;
28 | }
29 | .maplibregl-compare .compare-swiper-horizontal {
30 | background-color: #3887be;
31 | box-shadow: inset 0 0 0 2px #fff;
32 | display: inline-block;
33 | border-radius: 50%;
34 | position: absolute;
35 | width: 60px;
36 | height: 60px;
37 | top: 50%;
38 | left: 50%;
39 | margin: -30px 1px 0;
40 | color: #fff;
41 | cursor: ns-resize;
42 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjYwIiAgIGhlaWdodD0iNjAiICAgdmVyc2lvbj0iMS4xIiAgIHZpZXdCb3g9IjAgMCA2MCA2MCIgICBpZD0ic3ZnNTQzNCIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxK2RldmVsK29zeG1lbnUgcjEyOTExIiAgIHNvZGlwb2RpOmRvY25hbWU9Imwtci5zdmciPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE1NDQ0Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzNTQ0MiIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4NiIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlkPSJuYW1lZHZpZXc1NDQwIiAgICAgc2hvd2dyaWQ9InRydWUiICAgICBpbmtzY2FwZTp6b29tPSI0IiAgICAgaW5rc2NhcGU6Y3g9IjI1Ljg4OTgzMSIgICAgIGlua3NjYXBlOmN5PSIzNC4zODE4MzMiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIgICAgIGlua3NjYXBlOndpbmRvdy15PSIyMyIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc1NDM0IiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIiAgICAgaW5rc2NhcGU6c25hcC1zbW9vdGgtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkNTk4OSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPHBhdGggICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAgICAgZD0iTSAyNSAyNCBMIDE2IDMwIEwgMjUgMzYgTCAyNSAyNCB6IE0gMzUgMjQgTCAzNSAzNiBMIDQ0IDMwIEwgMzUgMjQgeiAiICAgICBpZD0icGF0aDU5OTUiIC8+PC9zdmc+);
43 | transform: rotate(90deg);
44 | }
45 |
--------------------------------------------------------------------------------
/dist/maplibre-gl-compare.js:
--------------------------------------------------------------------------------
1 | !function i(o,r,s){function h(t,e){if(!r[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}n=r[t]={exports:{}},o[t][0].call(n.exports,function(e){return h(o[t][1][e]||e)},n,n.exports,i,o,r,s)}return r[t].exports}for(var u="function"==typeof require&&require,e=0;ethis._bounds.width?this._bounds.width:e},_getY:function(e){e=(e=e.touches?e.touches[0]:e).clientY-this._bounds.top;return e=(e=e<0?0:e)>this._bounds.height?this._bounds.height:e},setSlider:function(e){this._setPosition(e)},on:function(e,t){return this._ev.on(e,t),this},fire:function(e,t){return this._ev.emit(e,t),this},off:function(e,t){return this._ev.removeListener(e,t),this},remove:function(){this._clearSync(),this._mapB.off("resize",this._onResize);var e=this._mapA.getContainer(),e=(e&&(e.style.clip=null,e.removeEventListener("mousemove",this._onMove)),this._mapB.getContainer());e&&(e.style.clip=null,e.removeEventListener("mousemove",this._onMove)),this._swiper.removeEventListener("mousedown",this._onDown),this._swiper.removeEventListener("touchstart",this._onDown),this._controlContainer.remove()}},window.maplibregl?maplibregl.Compare=i:void 0!==t&&(t.exports=i)},{"@mapbox/mapbox-gl-sync-move":2,events:3}],2:[function(e,t,n){t.exports=function(){var e=arguments.length;if(1===e)t=arguments[0];else for(var t=[],n=0;no&&!r.warned&&(r.warned=!0,(i=new Error("Possible EventEmitter memory leak detected. "+r.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit")).name="MaxListenersExceededWarning",i.emitter=e,i.type=t,i.count=r.length,n=i,console&&console.warn&&console.warn(n))),e}function h(e,t,n){e={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},t=function(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}.bind(e);return t.listener=n,e.wrapFn=t}function p(e,t,n){e=e._events;if(void 0===e)return[];e=e[t];{if(void 0===e)return[];if("function"==typeof e)return n?[e.listener||e]:[e];if(n){for(var i=e,o=new Array(i.length),r=0;r
2 |
3 |
4 |
5 |
6 |
10 |
11 |
15 |
16 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("../");
4 |
5 | // 'Before' style from https://github.com/lukasmartinelli/naturalearthtiles
6 | var before = new maplibregl.Map({
7 | container: "before",
8 | style: "https://raw.githubusercontent.com/lukasmartinelli/naturalearthtiles/gh-pages/maps/natural_earth.vector.json",
9 | zoom: 2
10 | });
11 |
12 | // 'After' style from https://github.com/maplibre/demotiles
13 | var after = new maplibregl.Map({
14 | container: "after",
15 | style: "https://demotiles.maplibre.org/style.json",
16 | zoom: 2
17 | });
18 |
19 | // Use either of these patterns to select a container for the compare widget
20 | var wrapperSelector = "#wrapper";
21 | var wrapperElement = document.body.querySelectorAll("#wrapper")[0];
22 |
23 | // available options
24 | var options = {
25 | mousemove: true,
26 | orientation: "horizontal",
27 | };
28 |
29 | window.compare = new maplibregl.Compare(
30 | before,
31 | after,
32 | wrapperSelector
33 | // options
34 | );
35 |
36 | var closeButton = document.getElementById("close-button");
37 |
38 | closeButton.addEventListener("click", function (e) {
39 | after.getContainer().style.display = "none";
40 | window.compare.remove();
41 | after.remove();
42 | });
43 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var syncMove = require("@mapbox/mapbox-gl-sync-move");
4 | var EventEmitter = require("events").EventEmitter;
5 |
6 | /**
7 | * @param {Object} a The first MapLibre GL Map
8 | * @param {Object} b The second MapLibre GL Map
9 | * @param {string|HTMLElement} container An HTML Element, or an element selector string for the compare container. It should be a wrapper around the two map Elements.
10 | * @param {Object} options
11 | * @param {string} [options.orientation=vertical] The orientation of the compare slider. `vertical` creates a vertical slider bar to compare one map on the left (map A) with another map on the right (map B). `horizontal` creates a horizontal slider bar to compare on mop on the top (map A) and another map on the bottom (map B).
12 | * @param {boolean} [options.mousemove=false] If `true` the compare slider will move with the cursor, otherwise the slider will need to be dragged to move.
13 | * @example
14 | * var compare = new maplibregl.Compare(beforeMap, afterMap, '#wrapper', {
15 | * orientation: 'vertical',
16 | * mousemove: true
17 | * });
18 | * @see [Swipe between maps](https://maplibre.org/maplibre-gl-js-docs/plugins/)
19 | */
20 | function Compare(a, b, container, options) {
21 | this.options = options ? options : {};
22 | this._mapA = a;
23 | this._mapB = b;
24 | this._horizontal = this.options.orientation === "horizontal";
25 | this._onDown = this._onDown.bind(this);
26 | this._onMove = this._onMove.bind(this);
27 | this._onMouseUp = this._onMouseUp.bind(this);
28 | this._onTouchEnd = this._onTouchEnd.bind(this);
29 | this._ev = new EventEmitter();
30 | this._swiper = document.createElement("div");
31 | this._swiper.className = this._horizontal
32 | ? "compare-swiper-horizontal"
33 | : "compare-swiper-vertical";
34 |
35 | this._controlContainer = document.createElement("div");
36 | this._controlContainer.className = this._horizontal
37 | ? "maplibregl-compare maplibregl-compare-horizontal"
38 | : "maplibregl-compare";
39 | this._controlContainer.className = this._controlContainer.className;
40 | this._controlContainer.appendChild(this._swiper);
41 |
42 | if (typeof container === "string" && document.body.querySelectorAll) {
43 | // get container with a selector
44 | var appendTarget = document.body.querySelectorAll(container)[0];
45 | if (!appendTarget) {
46 | throw new Error("Cannot find element with specified container selector.");
47 | }
48 | appendTarget.appendChild(this._controlContainer);
49 | } else if (container instanceof Element && container.appendChild) {
50 | // get container directly
51 | container.appendChild(this._controlContainer);
52 | } else {
53 | throw new Error(
54 | "Invalid container specified. Must be CSS selector or HTML element."
55 | );
56 | }
57 |
58 | this._bounds = b.getContainer().getBoundingClientRect();
59 | var swiperPosition =
60 | (this._horizontal ? this._bounds.height : this._bounds.width) / 2;
61 |
62 | this._setPosition(swiperPosition);
63 |
64 | this._clearSync = syncMove(a, b);
65 | this._onResize = function () {
66 | this._bounds = b.getContainer().getBoundingClientRect();
67 | if (this.currentPosition) this._setPosition(this.currentPosition);
68 | }.bind(this);
69 |
70 | b.on("resize", this._onResize);
71 |
72 | if (this.options && this.options.mousemove) {
73 | a.getContainer().addEventListener("mousemove", this._onMove);
74 | b.getContainer().addEventListener("mousemove", this._onMove);
75 | }
76 |
77 | this._swiper.addEventListener("mousedown", this._onDown);
78 | this._swiper.addEventListener("touchstart", this._onDown);
79 | }
80 |
81 | Compare.prototype = {
82 | _setPointerEvents: function (v) {
83 | this._controlContainer.style.pointerEvents = v;
84 | this._swiper.style.pointerEvents = v;
85 | },
86 |
87 | _onDown: function (e) {
88 | if (e.touches) {
89 | document.addEventListener("touchmove", this._onMove);
90 | document.addEventListener("touchend", this._onTouchEnd);
91 | } else {
92 | document.addEventListener("mousemove", this._onMove);
93 | document.addEventListener("mouseup", this._onMouseUp);
94 | }
95 | },
96 |
97 | _setPosition: function (x) {
98 | x = Math.min(
99 | x,
100 | this._horizontal ? this._bounds.height : this._bounds.width
101 | );
102 | var pos = this._horizontal
103 | ? "translate(0, " + x + "px)"
104 | : "translate(" + x + "px, 0)";
105 | this._controlContainer.style.transform = pos;
106 | this._controlContainer.style.WebkitTransform = pos;
107 | var clipA = this._horizontal
108 | ? "rect(0, 999em, " + x + "px, 0)"
109 | : "rect(0, " + x + "px, " + this._bounds.height + "px, 0)";
110 | var clipB = this._horizontal
111 | ? "rect(" + x + "px, 999em, " + this._bounds.height + "px,0)"
112 | : "rect(0, 999em, " + this._bounds.height + "px," + x + "px)";
113 |
114 | this._mapA.getContainer().style.clip = clipA;
115 | this._mapB.getContainer().style.clip = clipB;
116 | this.currentPosition = x;
117 | },
118 |
119 | _onMove: function (e) {
120 | if (this.options && this.options.mousemove) {
121 | this._setPointerEvents(e.touches ? "auto" : "none");
122 | }
123 |
124 | this._horizontal
125 | ? this._setPosition(this._getY(e))
126 | : this._setPosition(this._getX(e));
127 | },
128 |
129 | _onMouseUp: function () {
130 | document.removeEventListener("mousemove", this._onMove);
131 | document.removeEventListener("mouseup", this._onMouseUp);
132 | this.fire("slideend", { currentPosition: this.currentPosition });
133 | },
134 |
135 | _onTouchEnd: function () {
136 | document.removeEventListener("touchmove", this._onMove);
137 | document.removeEventListener("touchend", this._onTouchEnd);
138 | this.fire("slideend", { currentPosition: this.currentPosition });
139 | },
140 |
141 | _getX: function (e) {
142 | e = e.touches ? e.touches[0] : e;
143 | var x = e.clientX - this._bounds.left;
144 | if (x < 0) x = 0;
145 | if (x > this._bounds.width) x = this._bounds.width;
146 | return x;
147 | },
148 |
149 | _getY: function (e) {
150 | e = e.touches ? e.touches[0] : e;
151 | var y = e.clientY - this._bounds.top;
152 | if (y < 0) y = 0;
153 | if (y > this._bounds.height) y = this._bounds.height;
154 | return y;
155 | },
156 |
157 | /**
158 | * Set the position of the slider.
159 | *
160 | * @param {number} x Slider position in pixels from left/top.
161 | */
162 | setSlider: function (x) {
163 | this._setPosition(x);
164 | },
165 |
166 | /**
167 | * Adds a listener for events of a specified type.
168 | *
169 | * @param {string} type The event type to listen for; one of `slideend`.
170 | * @param {Function} listener The function to be called when the event is fired.
171 | * @returns {Compare} `this`
172 | */
173 | on: function (type, fn) {
174 | this._ev.on(type, fn);
175 | return this;
176 | },
177 |
178 | /**
179 | * Fire an event of a specified type.
180 | *
181 | * @param {string} type The event type to fire; one of `slideend`.
182 | * @param {Object} data Data passed to the event listener.
183 | * @returns {Compare} `this`
184 | */
185 | fire: function (type, data) {
186 | this._ev.emit(type, data);
187 | return this;
188 | },
189 |
190 | /**
191 | * Removes an event listener previously added with `Compare#on`.
192 | *
193 | * @param {string} type The event type previously used to install the listener.
194 | * @param {Function} listener The function previously installed as a listener.
195 | * @returns {Compare} `this`
196 | */
197 | off: function (type, fn) {
198 | this._ev.removeListener(type, fn);
199 | return this;
200 | },
201 |
202 | remove: function () {
203 | this._clearSync();
204 | this._mapB.off("resize", this._onResize);
205 | var aContainer = this._mapA.getContainer();
206 |
207 | if (!!aContainer) {
208 | aContainer.style.clip = null;
209 | aContainer.removeEventListener("mousemove", this._onMove);
210 | }
211 |
212 | var bContainer = this._mapB.getContainer();
213 |
214 | if (!!bContainer) {
215 | bContainer.style.clip = null;
216 | bContainer.removeEventListener("mousemove", this._onMove);
217 | }
218 |
219 | this._swiper.removeEventListener("mousedown", this._onDown);
220 | this._swiper.removeEventListener("touchstart", this._onDown);
221 | this._controlContainer.remove();
222 | },
223 | };
224 |
225 | if (window.maplibregl) {
226 | maplibregl.Compare = Compare;
227 | } else if (typeof module !== "undefined") {
228 | module.exports = Compare;
229 | }
230 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@maplibre/maplibre-gl-compare",
3 | "version": "0.6.0-dev",
4 | "description": "Swipe and sync between two MapLibre maps",
5 | "funding": "https://github.com/maplibre/maplibre-gl-js?sponsor=1",
6 | "main": "index.js",
7 | "directories": {
8 | "example": "example"
9 | },
10 | "scripts": {
11 | "start": "cp style.css example/style.css && budo example/index.js --serve example/bundle.js --dir example --live",
12 | "build": "cp style.css dist/maplibre-gl-compare.css && NODE_ENV=production && browserify index.js | uglifyjs -c -m > dist/maplibre-gl-compare.js",
13 | "test": "npm run lint && browserify -t envify test/index.js | smokestack -b firefox | tap-status",
14 | "lint": "eslint --no-eslintrc -c .eslintrc index.js example/index.js test/index.js",
15 | "docs": "documentation build index.js --format=md > API.md"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/maplibre/maplibre-gl-compare.git"
20 | },
21 | "keywords": [
22 | "maplibre",
23 | "maplibregl",
24 | "maps",
25 | "gl",
26 | "ui"
27 | ],
28 | "license": "ISC",
29 | "devDependencies": {
30 | "browserify": "^17.0.0",
31 | "budo": "^11.6.4",
32 | "documentation": "^13.2.5",
33 | "envify": "^4.1.0",
34 | "eslint": "^8.9.0",
35 | "maplibre-gl": "^2.1.6",
36 | "smokestack": "^3.6.0",
37 | "tap-status": "^1.0.1",
38 | "tape": "^5.5.2",
39 | "uglify-js": "^3.15.1"
40 | },
41 | "dependencies": {
42 | "@mapbox/mapbox-gl-sync-move": "^0.3.0"
43 | },
44 | "peerDependencies": {
45 | "maplibre-gl": ">=2.1.6"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | .maplibregl-compare {
2 | background-color: #fff;
3 | position: absolute;
4 | width: 2px;
5 | height: 100%;
6 | z-index: 1;
7 | }
8 | .maplibregl-compare .compare-swiper-vertical {
9 | background-color: #3887be;
10 | box-shadow: inset 0 0 0 2px #fff;
11 | display: inline-block;
12 | border-radius: 50%;
13 | position: absolute;
14 | width: 60px;
15 | height: 60px;
16 | top: 50%;
17 | left: -30px;
18 | margin: -30px 1px 0;
19 | color: #fff;
20 | cursor: ew-resize;
21 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjYwIiAgIGhlaWdodD0iNjAiICAgdmVyc2lvbj0iMS4xIiAgIHZpZXdCb3g9IjAgMCA2MCA2MCIgICBpZD0ic3ZnNTQzNCIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxK2RldmVsK29zeG1lbnUgcjEyOTExIiAgIHNvZGlwb2RpOmRvY25hbWU9Imwtci5zdmciPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE1NDQ0Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzNTQ0MiIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4NiIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlkPSJuYW1lZHZpZXc1NDQwIiAgICAgc2hvd2dyaWQ9InRydWUiICAgICBpbmtzY2FwZTp6b29tPSI0IiAgICAgaW5rc2NhcGU6Y3g9IjI1Ljg4OTgzMSIgICAgIGlua3NjYXBlOmN5PSIzNC4zODE4MzMiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIgICAgIGlua3NjYXBlOndpbmRvdy15PSIyMyIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc1NDM0IiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIiAgICAgaW5rc2NhcGU6c25hcC1zbW9vdGgtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkNTk4OSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPHBhdGggICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAgICAgZD0iTSAyNSAyNCBMIDE2IDMwIEwgMjUgMzYgTCAyNSAyNCB6IE0gMzUgMjQgTCAzNSAzNiBMIDQ0IDMwIEwgMzUgMjQgeiAiICAgICBpZD0icGF0aDU5OTUiIC8+PC9zdmc+);
22 | }
23 |
24 | .maplibregl-compare-horizontal {
25 | position: relative;
26 | width: 100%;
27 | height: 2px;
28 | }
29 | .maplibregl-compare .compare-swiper-horizontal {
30 | background-color: #3887be;
31 | box-shadow: inset 0 0 0 2px #fff;
32 | display: inline-block;
33 | border-radius: 50%;
34 | position: absolute;
35 | width: 60px;
36 | height: 60px;
37 | top: 50%;
38 | left: 50%;
39 | margin: -30px 1px 0;
40 | color: #fff;
41 | cursor: ns-resize;
42 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIgICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiICAgd2lkdGg9IjYwIiAgIGhlaWdodD0iNjAiICAgdmVyc2lvbj0iMS4xIiAgIHZpZXdCb3g9IjAgMCA2MCA2MCIgICBpZD0ic3ZnNTQzNCIgICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxK2RldmVsK29zeG1lbnUgcjEyOTExIiAgIHNvZGlwb2RpOmRvY25hbWU9Imwtci5zdmciPiAgPG1ldGFkYXRhICAgICBpZD0ibWV0YWRhdGE1NDQ0Ij4gICAgPHJkZjpSREY+ICAgICAgPGNjOldvcmsgICAgICAgICByZGY6YWJvdXQ9IiI+ICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4gICAgICAgIDxkYzp0eXBlICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+ICAgICAgPC9jYzpXb3JrPiAgICA8L3JkZjpSREY+ICA8L21ldGFkYXRhPiAgPGRlZnMgICAgIGlkPSJkZWZzNTQ0MiIgLz4gIDxzb2RpcG9kaTpuYW1lZHZpZXcgICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IiAgICAgYm9yZGVyb3BhY2l0eT0iMSIgICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiICAgICBncmlkdG9sZXJhbmNlPSIxMCIgICAgIGd1aWRldG9sZXJhbmNlPSIxMCIgICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIgICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI4NiIgICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijc1MSIgICAgIGlkPSJuYW1lZHZpZXc1NDQwIiAgICAgc2hvd2dyaWQ9InRydWUiICAgICBpbmtzY2FwZTp6b29tPSI0IiAgICAgaW5rc2NhcGU6Y3g9IjI1Ljg4OTgzMSIgICAgIGlua3NjYXBlOmN5PSIzNC4zODE4MzMiICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIgICAgIGlua3NjYXBlOndpbmRvdy15PSIyMyIgICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmc1NDM0IiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIiAgICAgaW5rc2NhcGU6c25hcC1zbW9vdGgtbm9kZXM9InRydWUiPiAgICA8aW5rc2NhcGU6Z3JpZCAgICAgICB0eXBlPSJ4eWdyaWQiICAgICAgIGlkPSJncmlkNTk4OSIgLz4gIDwvc29kaXBvZGk6bmFtZWR2aWV3PiAgPHBhdGggICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjFweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAgICAgZD0iTSAyNSAyNCBMIDE2IDMwIEwgMjUgMzYgTCAyNSAyNCB6IE0gMzUgMjQgTCAzNSAzNiBMIDQ0IDMwIEwgMzUgMjQgeiAiICAgICBpZD0icGF0aDU5OTUiIC8+PC9zdmc+);
43 | transform: rotate(90deg);
44 | }
45 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tape');
4 | window.maplibregl = require('maplibre-gl');
5 | require('../');
6 |
7 | // Tests
8 | test('Compare', function (t) {
9 | var a = new maplibregl.Map({
10 | container: document.createElement('div'),
11 | style: 'https://demotiles.maplibre.org/style.json',
12 | });
13 |
14 | var b = new maplibregl.Map({
15 | container: document.createElement('div'),
16 | style: 'https://demotiles.maplibre.org/style.json',
17 | });
18 |
19 | // insert the container's into the document so compare.setSlider test works
20 | document.body.appendChild(a.getContainer());
21 | document.body.appendChild(b.getContainer());
22 |
23 | var container = document.createElement('div');
24 |
25 | var compare = new maplibregl.Compare(a, b, container);
26 |
27 | t.ok(!!a.getContainer().style.clip, 'Map A is clipped');
28 | t.ok(!!b.getContainer().style.clip, 'Map B is clipped');
29 |
30 | b.jumpTo({
31 | bearing: 20,
32 | center: {
33 | lat: 16,
34 | lng: -155,
35 | },
36 | pitch: 20,
37 | zoom: 3,
38 | });
39 |
40 | t.equals(a.getZoom(), 3, 'Zoom is synched');
41 | t.equals(a.getPitch(), 20, 'Pitch is synched');
42 | t.equals(a.getBearing(), 20, 'Bearing is synched');
43 | t.equals(a.getCenter().lng, -155, 'Lng is synched');
44 | t.equals(a.getCenter().lat, 16, 'Lat is synched');
45 |
46 | compare.setSlider(20);
47 |
48 | t.equals(compare.currentPosition, 20, 'Slider has been moved');
49 |
50 | compare.remove();
51 |
52 | t.ok(!a.getContainer().style.clip, 'Map A is no longer clipped');
53 | t.ok(!b.getContainer().style.clip, 'Map B is no longer clipped');
54 |
55 | b.jumpTo({
56 | bearing: 10,
57 | center: {
58 | lat: 26,
59 | lng: -105,
60 | },
61 | pitch: 30,
62 | zoom: 5,
63 | });
64 |
65 | t.equals(a.getZoom(), 3, 'Zoom is no longer synched');
66 | t.equals(a.getPitch(), 20, 'Pitch is no longer synched');
67 | t.equals(a.getBearing(), 20, 'Bearing is no longer synched');
68 | t.equals(a.getCenter().lng, -155, 'Lng is no longer synched');
69 | t.equals(a.getCenter().lat, 16, 'Lat is no longer synched');
70 |
71 | t.end();
72 | });
73 |
74 | // close the smokestack window once tests are complete
75 | test('shutdown', function (t) {
76 | t.end();
77 | setTimeout(function () {
78 | window.close();
79 | });
80 | });
81 |
--------------------------------------------------------------------------------