ts-maps 0.3.5 → 0.3.7
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.
|
@@ -1,12 +1,52 @@
|
|
|
1
1
|
import { Handler } from '../../core/Handler';
|
|
2
|
+
import type { LatLng } from '../../geo/LatLng';
|
|
2
3
|
import type { Point } from '../../geometry/Point';
|
|
4
|
+
/**
|
|
5
|
+
* Continuous scroll-wheel zoom.
|
|
6
|
+
*
|
|
7
|
+
* The previous implementation was Leaflet's: accumulate wheel delta, wait
|
|
8
|
+
* 40ms for the gesture to stop, then animate one discrete `setZoom` step. That
|
|
9
|
+
* is three separate problems stacked on each other — the map does not move
|
|
10
|
+
* while you are actually scrolling, it then moves in a jump you did not ask
|
|
11
|
+
* for, and a trackpad's continuous stream of small deltas is chopped into a
|
|
12
|
+
* sequence of those jumps. Next to Google Maps or Apple Maps it reads as
|
|
13
|
+
* broken rather than as slow.
|
|
14
|
+
*
|
|
15
|
+
* What every other slippy map does instead, and what this does:
|
|
16
|
+
*
|
|
17
|
+
* - Wheel events push a TARGET zoom. They never animate anything themselves,
|
|
18
|
+
* so a fast scroll and a slow one differ in how far they go, not in how
|
|
19
|
+
* many animations they queue.
|
|
20
|
+
* - A single rAF loop eases the live zoom toward that target and stops when
|
|
21
|
+
* it arrives. Scrolling again just moves the target; the loop is already
|
|
22
|
+
* running and simply keeps going. There is nothing to cancel and nothing
|
|
23
|
+
* to queue.
|
|
24
|
+
* - The point under the cursor stays under the cursor, recomputed every
|
|
25
|
+
* frame from the anchor the gesture started at.
|
|
26
|
+
*
|
|
27
|
+
* ## Trackpads
|
|
28
|
+
*
|
|
29
|
+
* A pinch on a macOS trackpad arrives as a `wheel` event with `ctrlKey` set —
|
|
30
|
+
* the browser's way of reporting a zoom gesture, and nothing to do with the
|
|
31
|
+
* Control key. Those deltas are much finer than a mouse notch, so applying the
|
|
32
|
+
* mouse's px-per-level to them makes a pinch cover half the zoom range. They
|
|
33
|
+
* get their own scale, and no easing: a pinch is a direct manipulation, and
|
|
34
|
+
* anything that lags behind the fingers feels broken.
|
|
35
|
+
*/
|
|
3
36
|
export declare class ScrollWheelZoomHandler extends Handler {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
37
|
+
_targetZoom: number | null;
|
|
38
|
+
_anchor?: Point;
|
|
39
|
+
_anchorLatLng?: LatLng;
|
|
40
|
+
_frame?: number;
|
|
41
|
+
_lastFrameTime: number;
|
|
42
|
+
_active: boolean;
|
|
8
43
|
addHooks(): void;
|
|
9
44
|
removeHooks(): void;
|
|
10
|
-
_onWheelScroll(e:
|
|
11
|
-
|
|
45
|
+
_onWheelScroll(e: WheelEvent): void;
|
|
46
|
+
_applyZoom(zoom: number): void;
|
|
47
|
+
_startFrames(): void;
|
|
48
|
+
_stopFrames(): void;
|
|
49
|
+
_tick(timestamp: number): void;
|
|
50
|
+
_scheduleSettle(): void;
|
|
51
|
+
_settle(): void;
|
|
12
52
|
}
|
package/dist/index.js
CHANGED
|
@@ -11796,7 +11796,7 @@ function evaluateFilterLegacy(filter, feature) {
|
|
|
11796
11796
|
const key3 = rest[0];
|
|
11797
11797
|
return typeof key3 === "string" && !(key3 in feature.properties);
|
|
11798
11798
|
}
|
|
11799
|
-
const left =
|
|
11799
|
+
const left = resolveLegacyKey(rest[0], feature);
|
|
11800
11800
|
if (op === "==" || op === "!=") {
|
|
11801
11801
|
const right = resolveOperand(rest[1], feature);
|
|
11802
11802
|
return op === "==" ? left === right : left !== right;
|
|
@@ -11817,6 +11817,19 @@ function evaluateFilterLegacy(filter, feature) {
|
|
|
11817
11817
|
}
|
|
11818
11818
|
return true;
|
|
11819
11819
|
}
|
|
11820
|
+
function resolveLegacyKey(node, feature) {
|
|
11821
|
+
if (Array.isArray(node))
|
|
11822
|
+
return resolveOperand(node, feature);
|
|
11823
|
+
if (node === "$type") {
|
|
11824
|
+
const t = feature.type;
|
|
11825
|
+
return t === 1 ? "Point" : t === 2 ? "LineString" : t === 3 ? "Polygon" : "Unknown";
|
|
11826
|
+
}
|
|
11827
|
+
if (node === "$id")
|
|
11828
|
+
return feature.id ?? null;
|
|
11829
|
+
if (typeof node === "string")
|
|
11830
|
+
return feature.properties[node] ?? null;
|
|
11831
|
+
return node;
|
|
11832
|
+
}
|
|
11820
11833
|
function resolveOperand(node, feature) {
|
|
11821
11834
|
if (Array.isArray(node)) {
|
|
11822
11835
|
if (node[0] === "get" && typeof node[1] === "string")
|
|
@@ -23577,50 +23590,113 @@ init_DomEvent();
|
|
|
23577
23590
|
init_Map();
|
|
23578
23591
|
TsMap.mergeOptions({
|
|
23579
23592
|
scrollWheelZoom: true,
|
|
23580
|
-
|
|
23581
|
-
|
|
23593
|
+
wheelPxPerZoomLevel: 60,
|
|
23594
|
+
wheelSmoothing: 0.13,
|
|
23595
|
+
wheelDebounceTime: 40
|
|
23582
23596
|
});
|
|
23583
23597
|
|
|
23584
23598
|
class ScrollWheelZoomHandler extends Handler {
|
|
23585
|
-
_delta = 0;
|
|
23586
|
-
_startTime = null;
|
|
23587
23599
|
addHooks() {
|
|
23588
23600
|
on(this._map._container, "wheel", this._onWheelScroll, this);
|
|
23589
|
-
this.
|
|
23601
|
+
this._targetZoom = null;
|
|
23602
|
+
this._active = false;
|
|
23603
|
+
this._lastFrameTime = 0;
|
|
23590
23604
|
}
|
|
23591
23605
|
removeHooks() {
|
|
23592
23606
|
off(this._map._container, "wheel", this._onWheelScroll, this);
|
|
23593
|
-
|
|
23607
|
+
this._stopFrames();
|
|
23608
|
+
this._targetZoom = null;
|
|
23609
|
+
this._active = false;
|
|
23594
23610
|
}
|
|
23595
23611
|
_onWheelScroll(e) {
|
|
23612
|
+
const map = this._map;
|
|
23596
23613
|
const delta = getWheelDelta(e);
|
|
23597
|
-
const debounce = this._map.options.wheelDebounceTime;
|
|
23598
|
-
this._delta += delta;
|
|
23599
|
-
this._lastMousePos = this._map.pointerEventToContainerPoint(e);
|
|
23600
|
-
if (!this._startTime)
|
|
23601
|
-
this._startTime = Date.now();
|
|
23602
|
-
const left = Math.max(debounce - (Date.now() - this._startTime), 0);
|
|
23603
|
-
clearTimeout(this._timer);
|
|
23604
|
-
this._timer = setTimeout(this._performZoom.bind(this), left);
|
|
23605
23614
|
stop(e);
|
|
23615
|
+
if (!delta)
|
|
23616
|
+
return;
|
|
23617
|
+
const pinch = e.ctrlKey === true;
|
|
23618
|
+
const pxPerLevel = map.options.wheelPxPerZoomLevel;
|
|
23619
|
+
const step = delta / (pinch ? pxPerLevel * 2 : pxPerLevel);
|
|
23620
|
+
if (!this._active) {
|
|
23621
|
+
this._anchor = map.pointerEventToContainerPoint(e);
|
|
23622
|
+
this._anchorLatLng = map.containerPointToLatLng(this._anchor);
|
|
23623
|
+
this._targetZoom = map.getZoom();
|
|
23624
|
+
this._active = true;
|
|
23625
|
+
map._stop();
|
|
23626
|
+
map._moveStart(true, false);
|
|
23627
|
+
}
|
|
23628
|
+
this._targetZoom = map._limitZoom(this._targetZoom + step);
|
|
23629
|
+
if (pinch) {
|
|
23630
|
+
this._applyZoom(this._targetZoom);
|
|
23631
|
+
this._scheduleSettle();
|
|
23632
|
+
return;
|
|
23633
|
+
}
|
|
23634
|
+
if (this._frame === undefined)
|
|
23635
|
+
this._startFrames();
|
|
23606
23636
|
}
|
|
23607
|
-
|
|
23637
|
+
_applyZoom(zoom) {
|
|
23608
23638
|
const map = this._map;
|
|
23609
|
-
const
|
|
23610
|
-
const
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
const d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2;
|
|
23614
|
-
const d4 = snap ? Math.ceil(d3 / snap) * snap : d3;
|
|
23615
|
-
const delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
|
|
23616
|
-
this._delta = 0;
|
|
23617
|
-
this._startTime = null;
|
|
23618
|
-
if (!delta)
|
|
23639
|
+
const anchor = this._anchor;
|
|
23640
|
+
const anchorLatLng = this._anchorLatLng;
|
|
23641
|
+
if (!anchor || !anchorLatLng) {
|
|
23642
|
+
map._move(map.getCenter(), zoom);
|
|
23619
23643
|
return;
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23644
|
+
}
|
|
23645
|
+
const viewHalf = map.getSize().divideBy(2);
|
|
23646
|
+
const offset = anchor.subtract(viewHalf);
|
|
23647
|
+
const center = map.unproject(map.project(anchorLatLng, zoom).subtract(offset), zoom);
|
|
23648
|
+
map._move(center, zoom, { round: false });
|
|
23649
|
+
}
|
|
23650
|
+
_startFrames() {
|
|
23651
|
+
this._lastFrameTime = 0;
|
|
23652
|
+
this._frame = requestAnimationFrame((ts) => this._tick(ts));
|
|
23653
|
+
}
|
|
23654
|
+
_stopFrames() {
|
|
23655
|
+
if (this._frame !== undefined) {
|
|
23656
|
+
cancelAnimationFrame(this._frame);
|
|
23657
|
+
this._frame = undefined;
|
|
23658
|
+
}
|
|
23659
|
+
}
|
|
23660
|
+
_tick(timestamp) {
|
|
23661
|
+
const map = this._map;
|
|
23662
|
+
const target = this._targetZoom;
|
|
23663
|
+
if (target === null) {
|
|
23664
|
+
this._frame = undefined;
|
|
23665
|
+
return;
|
|
23666
|
+
}
|
|
23667
|
+
const dt = this._lastFrameTime ? Math.min((timestamp - this._lastFrameTime) / 1000, 0.1) : 1 / 60;
|
|
23668
|
+
this._lastFrameTime = timestamp;
|
|
23669
|
+
const smoothing = Math.max(0.01, map.options.wheelSmoothing);
|
|
23670
|
+
const t = 1 - Math.exp(-dt / smoothing);
|
|
23671
|
+
const current = map.getZoom();
|
|
23672
|
+
const remaining = target - current;
|
|
23673
|
+
if (Math.abs(remaining) < 0.001) {
|
|
23674
|
+
this._applyZoom(target);
|
|
23675
|
+
this._frame = undefined;
|
|
23676
|
+
this._settle();
|
|
23677
|
+
return;
|
|
23678
|
+
}
|
|
23679
|
+
this._applyZoom(current + remaining * t);
|
|
23680
|
+
this._frame = requestAnimationFrame((ts) => this._tick(ts));
|
|
23681
|
+
}
|
|
23682
|
+
_scheduleSettle() {
|
|
23683
|
+
this._stopFrames();
|
|
23684
|
+
this._frame = requestAnimationFrame(() => {
|
|
23685
|
+
this._frame = undefined;
|
|
23686
|
+
setTimeout(() => {
|
|
23687
|
+
if (this._frame === undefined && this._active)
|
|
23688
|
+
this._settle();
|
|
23689
|
+
}, 120);
|
|
23690
|
+
});
|
|
23691
|
+
}
|
|
23692
|
+
_settle() {
|
|
23693
|
+
if (!this._active)
|
|
23694
|
+
return;
|
|
23695
|
+
this._active = false;
|
|
23696
|
+
this._targetZoom = null;
|
|
23697
|
+
this._anchor = undefined;
|
|
23698
|
+
this._anchorLatLng = undefined;
|
|
23699
|
+
this._map._moveEnd(true);
|
|
23624
23700
|
}
|
|
23625
23701
|
}
|
|
23626
23702
|
TsMap.addInitHook("addHandler", "scrollWheelZoom", ScrollWheelZoomHandler);
|