|
1 |
| -import { Extent, numClamp, vecAdd } from '@rapid-sdk/math'; |
| 1 | +import { Extent, numClamp, vecAdd, vecLength } from '@rapid-sdk/math'; |
2 | 2 | import { easeLinear } from 'd3-ease';
|
3 | 3 | import { selection, select } from 'd3-selection';
|
4 | 4 | import * as Polyclip from 'polyclip-ts';
|
@@ -232,7 +232,30 @@ export class UiCurtain {
|
232 | 232 |
|
233 | 233 | const clipped = Polyclip.intersection([extentPolygon], [mapPolygon]);
|
234 | 234 | if (clipped?.length) {
|
235 |
| - this._revealPolygon = clipped[0][0]; // Polyclip returns a multipolygon |
| 235 | + // Polyclip returns a MultiPolygon with outer ring wound "counterclockwise". |
| 236 | + // However it assumes that the input is GeoJSON, which has a coordinate system |
| 237 | + // where +y goes up. So when we work in screen coordinates where +y goes down, |
| 238 | + // we actually get a "clockwise" result and need to reverse it. |
| 239 | + const ring = clipped[0][0].reverse(); |
| 240 | + |
| 241 | + // Pick the point closest to the top-left corner to start the ring - Rapid#1674 |
| 242 | + const len = ring.length - 1; // ring is closed, can skip last one |
| 243 | + let minDist = Infinity; |
| 244 | + let minIndex = 0; |
| 245 | + |
| 246 | + for (let i = 0; i < len; i++) { |
| 247 | + const dist = vecLength(ring[i], [0, 0]); |
| 248 | + if (dist < minDist) { |
| 249 | + minDist = dist; |
| 250 | + minIndex = i; |
| 251 | + } |
| 252 | + } |
| 253 | + this._revealPolygon = []; |
| 254 | + for (let i = 0; i < len; i++) { |
| 255 | + const fromIndex = (i + minIndex) % len; |
| 256 | + this._revealPolygon[i] = ring[fromIndex]; |
| 257 | + } |
| 258 | + this._revealPolygon.push(this._revealPolygon[0]); // close ring |
236 | 259 | }
|
237 | 260 |
|
238 | 261 | // A D3-selector selector or a DOMElement (in screen coordinates)
|
|
0 commit comments