-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathAnimateUtil.ts
92 lines (84 loc) · 2.99 KB
/
AnimateUtil.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import _isFunction from 'lodash/isFunction';
import _isNil from 'lodash/isNil';
import OlFeature from 'ol/Feature';
import OlGeometry from 'ol/geom/Geometry';
import OlLayerVector from 'ol/layer/Vector';
import OlMap from 'ol/Map';
import { unByKey } from 'ol/Observable';
import { getVectorContext } from 'ol/render';
import OlSourceVector from 'ol/source/Vector';
import OlStyle from 'ol/style/Style';
/**
* This class provides some static methods which might be helpful when working
* with digitize functions to animate features.
*
* @class AnimateUtil
*/
class AnimateUtil {
/**
* Moves / translates an `OlFeature` to the given `pixel` delta
* in the end with given `duration` in ms, using the given style.
*
* @param {import("ol/Map").default} map An OlMap.
* @param {import("ol/layer/Vector").default<import("ol/source/Vector").default>} layer A vector layer to receive a
* postrender event.
* @param {import("ol/Feature").default} featureToMove The feature to move.
* @param {number} duration The duration in ms for the moving to complete.
* @param {number} pixel Delta of pixels to move the feature.
* @param {import("ol/style/Style").default} [style] The style to use when moving the feature.
*
* @return {Promise<import("ol/Feature").default>} Promise of the moved feature.
*/
static moveFeature(
map: OlMap,
layer: OlLayerVector<OlSourceVector>,
featureToMove: OlFeature<OlGeometry>,
duration: number,
pixel: number,
style: OlStyle
): Promise<OlFeature<OlGeometry>> {
return new Promise(resolve => {
const geometry = featureToMove.getGeometry();
if (_isNil(geometry)) {
throw new Error('Feature has no geometry.');
}
const start = Date.now();
const resolution = map.getView().getResolution() ?? 0;
const totalDisplacement = pixel * resolution;
const expectedFrames = duration / 1000 * 60;
let actualFrames = 0;
const deltaX = totalDisplacement / expectedFrames;
const deltaY = totalDisplacement / expectedFrames;
/**
* Moves the feature `pixel` right and `pixel` up.
* @ignore
*/
const listenerKey = layer.on('postrender', (event) => {
const vectorContext = getVectorContext(event);
const frameState = event.frameState;
if (!frameState) {
return;
}
const elapsed = frameState.time - start;
geometry.translate(deltaX, deltaY);
if (style) {
if (_isFunction(style)) {
vectorContext.setStyle(style(featureToMove));
} else {
vectorContext.setStyle(style);
}
}
vectorContext.drawGeometry(geometry);
if (elapsed > duration || actualFrames >= expectedFrames) {
unByKey(listenerKey);
resolve(featureToMove);
}
// tell OpenLayers to continue postrender animation
frameState.animate = true;
actualFrames++;
map.render();
});
});
}
}
export default AnimateUtil;