@mapsight/lib-ol 4.0.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/README.md +20 -0
- package/dist/coordinate/add.d.ts +3 -0
- package/dist/coordinate/add.d.ts.map +1 -0
- package/dist/coordinate/add.js +8 -0
- package/dist/coordinate/add.js.map +1 -0
- package/dist/coordinate/addPixelPadding.d.ts +10 -0
- package/dist/coordinate/addPixelPadding.d.ts.map +1 -0
- package/dist/coordinate/addPixelPadding.js +13 -0
- package/dist/coordinate/addPixelPadding.js.map +1 -0
- package/dist/coordinate/fromPixel.d.ts +3 -0
- package/dist/coordinate/fromPixel.d.ts.map +1 -0
- package/dist/coordinate/fromPixel.js +8 -0
- package/dist/coordinate/fromPixel.js.map +1 -0
- package/dist/coordinate/scale.d.ts +3 -0
- package/dist/coordinate/scale.d.ts.map +1 -0
- package/dist/coordinate/scale.js +5 -0
- package/dist/coordinate/scale.js.map +1 -0
- package/dist/coordinate/toPixel.d.ts +3 -0
- package/dist/coordinate/toPixel.d.ts.map +1 -0
- package/dist/coordinate/toPixel.js +8 -0
- package/dist/coordinate/toPixel.js.map +1 -0
- package/dist/coordinates/equals.d.ts +3 -0
- package/dist/coordinates/equals.d.ts.map +1 -0
- package/dist/coordinates/equals.js +5 -0
- package/dist/coordinates/equals.js.map +1 -0
- package/dist/coordinates/middleCoordinate.d.ts +3 -0
- package/dist/coordinates/middleCoordinate.d.ts.map +1 -0
- package/dist/coordinates/middleCoordinate.js +5 -0
- package/dist/coordinates/middleCoordinate.js.map +1 -0
- package/dist/events/condition/clickOnFeature.d.ts +9 -0
- package/dist/events/condition/clickOnFeature.d.ts.map +1 -0
- package/dist/events/condition/clickOnFeature.js +10 -0
- package/dist/events/condition/clickOnFeature.js.map +1 -0
- package/dist/extent/getCentroid.d.ts +6 -0
- package/dist/extent/getCentroid.d.ts.map +1 -0
- package/dist/extent/getCentroid.js +9 -0
- package/dist/extent/getCentroid.js.map +1 -0
- package/dist/extent/isFiniteExtent.d.ts +3 -0
- package/dist/extent/isFiniteExtent.d.ts.map +1 -0
- package/dist/extent/isFiniteExtent.js +4 -0
- package/dist/extent/isFiniteExtent.js.map +1 -0
- package/dist/extents/combineExtents.d.ts +3 -0
- package/dist/extents/combineExtents.d.ts.map +1 -0
- package/dist/extents/combineExtents.js +9 -0
- package/dist/extents/combineExtents.js.map +1 -0
- package/dist/feature/animator.d.ts +9 -0
- package/dist/feature/animator.d.ts.map +1 -0
- package/dist/feature/animator.js +33 -0
- package/dist/feature/animator.js.map +1 -0
- package/dist/feature/cluster.d.ts +8 -0
- package/dist/feature/cluster.d.ts.map +1 -0
- package/dist/feature/cluster.js +50 -0
- package/dist/feature/cluster.js.map +1 -0
- package/dist/feature/detectFeatureHits.d.ts +11 -0
- package/dist/feature/detectFeatureHits.d.ts.map +1 -0
- package/dist/feature/detectFeatureHits.js +34 -0
- package/dist/feature/detectFeatureHits.js.map +1 -0
- package/dist/feature/ensureId.d.ts +3 -0
- package/dist/feature/ensureId.d.ts.map +1 -0
- package/dist/feature/ensureId.js +7 -0
- package/dist/feature/ensureId.js.map +1 -0
- package/dist/feature/getCentroid.d.ts +3 -0
- package/dist/feature/getCentroid.d.ts.map +1 -0
- package/dist/feature/getCentroid.js +13 -0
- package/dist/feature/getCentroid.js.map +1 -0
- package/dist/feature/getExtent.d.ts +3 -0
- package/dist/feature/getExtent.d.ts.map +1 -0
- package/dist/feature/getExtent.js +8 -0
- package/dist/feature/getExtent.js.map +1 -0
- package/dist/feature/getLayer.d.ts +4 -0
- package/dist/feature/getLayer.d.ts.map +1 -0
- package/dist/feature/getLayer.js +23 -0
- package/dist/feature/getLayer.js.map +1 -0
- package/dist/feature/getUid.d.ts +3 -0
- package/dist/feature/getUid.d.ts.map +1 -0
- package/dist/feature/getUid.js +5 -0
- package/dist/feature/getUid.js.map +1 -0
- package/dist/features/getCentroidForFeatures.d.ts +3 -0
- package/dist/features/getCentroidForFeatures.d.ts.map +1 -0
- package/dist/features/getCentroidForFeatures.js +7 -0
- package/dist/features/getCentroidForFeatures.js.map +1 -0
- package/dist/features/getExtentForFeatures.d.ts +3 -0
- package/dist/features/getExtentForFeatures.d.ts.map +1 -0
- package/dist/features/getExtentForFeatures.js +7 -0
- package/dist/features/getExtentForFeatures.js.map +1 -0
- package/dist/geometry/deriveGeometriesFromBase.d.ts +8 -0
- package/dist/geometry/deriveGeometriesFromBase.d.ts.map +1 -0
- package/dist/geometry/deriveGeometriesFromBase.js +69 -0
- package/dist/geometry/deriveGeometriesFromBase.js.map +1 -0
- package/dist/geometry/getDominantGeometryType.d.ts +4 -0
- package/dist/geometry/getDominantGeometryType.d.ts.map +1 -0
- package/dist/geometry/getDominantGeometryType.js +30 -0
- package/dist/geometry/getDominantGeometryType.js.map +1 -0
- package/dist/geometry/getLineStringSegmentVerticesWithRotation.d.ts +4 -0
- package/dist/geometry/getLineStringSegmentVerticesWithRotation.d.ts.map +1 -0
- package/dist/geometry/getLineStringSegmentVerticesWithRotation.js +28 -0
- package/dist/geometry/getLineStringSegmentVerticesWithRotation.js.map +1 -0
- package/dist/geometry/getPolygonRingSegmentVerticesWithRotation.d.ts +4 -0
- package/dist/geometry/getPolygonRingSegmentVerticesWithRotation.d.ts.map +1 -0
- package/dist/geometry/getPolygonRingSegmentVerticesWithRotation.js +49 -0
- package/dist/geometry/getPolygonRingSegmentVerticesWithRotation.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/map/animateDuringTransition.d.ts +4 -0
- package/dist/map/animateDuringTransition.d.ts.map +1 -0
- package/dist/map/animateDuringTransition.js +41 -0
- package/dist/map/animateDuringTransition.js.map +1 -0
- package/dist/map/canvasSizeFixer.d.ts +10 -0
- package/dist/map/canvasSizeFixer.d.ts.map +1 -0
- package/dist/map/canvasSizeFixer.js +35 -0
- package/dist/map/canvasSizeFixer.js.map +1 -0
- package/dist/map/containsExtentWithPadding.d.ts +5 -0
- package/dist/map/containsExtentWithPadding.d.ts.map +1 -0
- package/dist/map/containsExtentWithPadding.js +9 -0
- package/dist/map/containsExtentWithPadding.js.map +1 -0
- package/dist/map/fitToExtent.d.ts +10 -0
- package/dist/map/fitToExtent.d.ts.map +1 -0
- package/dist/map/fitToExtent.js +26 -0
- package/dist/map/fitToExtent.js.map +1 -0
- package/dist/map/fitToFeature.d.ts +17 -0
- package/dist/map/fitToFeature.d.ts.map +1 -0
- package/dist/map/fitToFeature.js +16 -0
- package/dist/map/fitToFeature.js.map +1 -0
- package/dist/map/fitToFeatures.d.ts +17 -0
- package/dist/map/fitToFeatures.d.ts.map +1 -0
- package/dist/map/fitToFeatures.js +11 -0
- package/dist/map/fitToFeatures.js.map +1 -0
- package/dist/map/getPaddedViewExtent.d.ts +5 -0
- package/dist/map/getPaddedViewExtent.d.ts.map +1 -0
- package/dist/map/getPaddedViewExtent.js +28 -0
- package/dist/map/getPaddedViewExtent.js.map +1 -0
- package/dist/map/getVisibleLayersFromFramestate.d.ts +5 -0
- package/dist/map/getVisibleLayersFromFramestate.d.ts.map +1 -0
- package/dist/map/getVisibleLayersFromFramestate.js +8 -0
- package/dist/map/getVisibleLayersFromFramestate.js.map +1 -0
- package/dist/map/updateSizeDuringTransition.d.ts +3 -0
- package/dist/map/updateSizeDuringTransition.d.ts.map +1 -0
- package/dist/map/updateSizeDuringTransition.js +7 -0
- package/dist/map/updateSizeDuringTransition.js.map +1 -0
- package/dist/map/updateSizeOnTransitionEnd.d.ts +3 -0
- package/dist/map/updateSizeOnTransitionEnd.d.ts.map +1 -0
- package/dist/map/updateSizeOnTransitionEnd.js +19 -0
- package/dist/map/updateSizeOnTransitionEnd.js.map +1 -0
- package/dist/points/findClosestPoint.d.ts +11 -0
- package/dist/points/findClosestPoint.d.ts.map +1 -0
- package/dist/points/findClosestPoint.js +32 -0
- package/dist/points/findClosestPoint.js.map +1 -0
- package/dist/points/spreadPointClusterInRadius.d.ts +14 -0
- package/dist/points/spreadPointClusterInRadius.d.ts.map +1 -0
- package/dist/points/spreadPointClusterInRadius.js +53 -0
- package/dist/points/spreadPointClusterInRadius.js.map +1 -0
- package/dist/style/bindStyleToGeometry.d.ts +4 -0
- package/dist/style/bindStyleToGeometry.d.ts.map +1 -0
- package/dist/style/bindStyleToGeometry.js +6 -0
- package/dist/style/bindStyleToGeometry.js.map +1 -0
- package/dist/style/createCachedStyleFunction.d.ts +45 -0
- package/dist/style/createCachedStyleFunction.d.ts.map +1 -0
- package/dist/style/createCachedStyleFunction.js +175 -0
- package/dist/style/createCachedStyleFunction.js.map +1 -0
- package/dist/style/declarationToGeometry.d.ts +3 -0
- package/dist/style/declarationToGeometry.d.ts.map +1 -0
- package/dist/style/declarationToGeometry.js +4 -0
- package/dist/style/declarationToGeometry.js.map +1 -0
- package/dist/style/declarationToStyle.d.ts +6 -0
- package/dist/style/declarationToStyle.d.ts.map +1 -0
- package/dist/style/declarationToStyle.js +167 -0
- package/dist/style/declarationToStyle.js.map +1 -0
- package/dist/style/styleFunction.d.ts +21 -0
- package/dist/style/styleFunction.d.ts.map +1 -0
- package/dist/style/styleFunction.js +13 -0
- package/dist/style/styleFunction.js.map +1 -0
- package/dist/tileGrid/getTileUrlsForExtent.d.ts +4 -0
- package/dist/tileGrid/getTileUrlsForExtent.d.ts.map +1 -0
- package/dist/tileGrid/getTileUrlsForExtent.js +23 -0
- package/dist/tileGrid/getTileUrlsForExtent.js.map +1 -0
- package/dist/view/centerOnFeature.d.ts +10 -0
- package/dist/view/centerOnFeature.d.ts.map +1 -0
- package/dist/view/centerOnFeature.js +12 -0
- package/dist/view/centerOnFeature.js.map +1 -0
- package/dist/view/centerOnFeatures.d.ts +8 -0
- package/dist/view/centerOnFeatures.d.ts.map +1 -0
- package/dist/view/centerOnFeatures.js +19 -0
- package/dist/view/centerOnFeatures.js.map +1 -0
- package/dist/view/getMinZoomFittingContentInView.d.ts +15 -0
- package/dist/view/getMinZoomFittingContentInView.d.ts.map +1 -0
- package/dist/view/getMinZoomFittingContentInView.js +29 -0
- package/dist/view/getMinZoomFittingContentInView.js.map +1 -0
- package/package.json +36 -0
- package/src/js/coordinate/add.ts +13 -0
- package/src/js/coordinate/addPixelPadding.ts +21 -0
- package/src/js/coordinate/fromPixel.ts +10 -0
- package/src/js/coordinate/scale.ts +7 -0
- package/src/js/coordinate/toPixel.ts +13 -0
- package/src/js/coordinates/equals.ts +6 -0
- package/src/js/coordinates/middleCoordinate.ts +7 -0
- package/src/js/events/condition/clickOnFeature.ts +13 -0
- package/src/js/extent/getCentroid.ts +14 -0
- package/src/js/extent/isFiniteExtent.ts +7 -0
- package/src/js/extents/combineExtents.ts +11 -0
- package/src/js/feature/animator.ts +91 -0
- package/src/js/feature/cluster.ts +86 -0
- package/src/js/feature/detectFeatureHits.ts +57 -0
- package/src/js/feature/ensureId.ts +9 -0
- package/src/js/feature/getCentroid.ts +18 -0
- package/src/js/feature/getExtent.ts +10 -0
- package/src/js/feature/getLayer.ts +39 -0
- package/src/js/feature/getUid.ts +6 -0
- package/src/js/features/getCentroidForFeatures.ts +10 -0
- package/src/js/features/getExtentForFeatures.ts +10 -0
- package/src/js/geometry/deriveGeometriesFromBase.ts +122 -0
- package/src/js/geometry/getDominantGeometryType.ts +40 -0
- package/src/js/geometry/getLineStringSegmentVerticesWithRotation.ts +48 -0
- package/src/js/geometry/getPolygonRingSegmentVerticesWithRotation.ts +90 -0
- package/src/js/index.ts +62 -0
- package/src/js/map/animateDuringTransition.ts +58 -0
- package/src/js/map/canvasSizeFixer.ts +46 -0
- package/src/js/map/containsExtentWithPadding.ts +17 -0
- package/src/js/map/fitToExtent.ts +45 -0
- package/src/js/map/fitToFeature.ts +29 -0
- package/src/js/map/fitToFeatures.ts +21 -0
- package/src/js/map/getPaddedViewExtent.ts +42 -0
- package/src/js/map/getVisibleLayersFromFramestate.ts +14 -0
- package/src/js/map/updateSizeDuringTransition.ts +9 -0
- package/src/js/map/updateSizeOnTransitionEnd.ts +28 -0
- package/src/js/points/findClosestPoint.ts +51 -0
- package/src/js/points/spreadPointClusterInRadius.ts +84 -0
- package/src/js/style/bindStyleToGeometry.ts +11 -0
- package/src/js/style/createCachedStyleFunction.ts +344 -0
- package/src/js/style/declarationToGeometry.ts +7 -0
- package/src/js/style/declarationToStyle.ts +277 -0
- package/src/js/style/styleFunction.ts +42 -0
- package/src/js/tileGrid/getTileUrlsForExtent.ts +41 -0
- package/src/js/view/centerOnFeature.ts +23 -0
- package/src/js/view/centerOnFeatures.ts +30 -0
- package/src/js/view/getMinZoomFittingContentInView.ts +50 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// EXAMPLE:
|
|
2
|
+
//
|
|
3
|
+
//var animator = FeatureAnimator(ol, map, function (feature, vectorContext, time) {
|
|
4
|
+
// switch (feature.getGeometry().getType()) {
|
|
5
|
+
// case 'Polygon':
|
|
6
|
+
// var strokeStyle = new ol.style.Stroke({
|
|
7
|
+
// color: 'red',
|
|
8
|
+
// width: 4 * ol.easing.easeOut(time)
|
|
9
|
+
// });
|
|
10
|
+
// var fillStyle = new ol.style.Fill({
|
|
11
|
+
// color: 'yellow'
|
|
12
|
+
// });
|
|
13
|
+
//
|
|
14
|
+
// vectorContext.setFillStrokeStyle(fillStyle, strokeStyle);
|
|
15
|
+
// vectorContext.drawPolygonGeometry(feature.getGeometry().clone(), null);
|
|
16
|
+
//
|
|
17
|
+
// break;
|
|
18
|
+
// default:
|
|
19
|
+
// }
|
|
20
|
+
//});
|
|
21
|
+
//
|
|
22
|
+
//if (!ol.has.TOUCH) {
|
|
23
|
+
// FeatureHitDetector(
|
|
24
|
+
// map,
|
|
25
|
+
// function (feature) {
|
|
26
|
+
// animator.start(feature);
|
|
27
|
+
// map.render();
|
|
28
|
+
// $map.addClass('feature-is-hit');
|
|
29
|
+
// },
|
|
30
|
+
// function (feature) {
|
|
31
|
+
// animator.stop();
|
|
32
|
+
// map.render();
|
|
33
|
+
// $map.removeClass('feature-is-hit');
|
|
34
|
+
// }
|
|
35
|
+
// );
|
|
36
|
+
//}
|
|
37
|
+
import type Feature from "ol/Feature";
|
|
38
|
+
import type OlMap from "ol/Map";
|
|
39
|
+
import {unByKey} from "ol/Observable";
|
|
40
|
+
import type {EventsKey} from "ol/events";
|
|
41
|
+
import {getVectorContext} from "ol/render";
|
|
42
|
+
import type RenderEvent from "ol/render/Event";
|
|
43
|
+
import type VectorContext from "ol/render/VectorContext";
|
|
44
|
+
|
|
45
|
+
export type AnimationFunction = (
|
|
46
|
+
feature: Feature,
|
|
47
|
+
vectorContext: VectorContext,
|
|
48
|
+
progress: number,
|
|
49
|
+
) => void;
|
|
50
|
+
|
|
51
|
+
export default function animator(
|
|
52
|
+
map: OlMap,
|
|
53
|
+
animationFunction: AnimationFunction,
|
|
54
|
+
duration = 2000,
|
|
55
|
+
) {
|
|
56
|
+
let listenerKey: EventsKey;
|
|
57
|
+
let isStopped = true;
|
|
58
|
+
|
|
59
|
+
function start(feature: Feature) {
|
|
60
|
+
const startTime = new Date().getTime();
|
|
61
|
+
|
|
62
|
+
function animate(event: RenderEvent) {
|
|
63
|
+
if (isStopped || !event.frameState) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const vectorContext = getVectorContext(event);
|
|
68
|
+
|
|
69
|
+
const elapsedTime = event.frameState.time - startTime;
|
|
70
|
+
animationFunction(feature, vectorContext, elapsedTime / duration);
|
|
71
|
+
|
|
72
|
+
if (elapsedTime > duration) {
|
|
73
|
+
stop();
|
|
74
|
+
} else {
|
|
75
|
+
event.frameState.animate = true; // tell OL3 to continue postcompose animation
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
isStopped = false;
|
|
80
|
+
listenerKey = map.on("postcompose", animate);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function stop() {
|
|
84
|
+
if (!isStopped) {
|
|
85
|
+
isStopped = true;
|
|
86
|
+
unByKey(listenerKey);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {start: start, stop: stop};
|
|
91
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Feature from "ol/Feature";
|
|
2
|
+
import type {Coordinate} from "ol/coordinate";
|
|
3
|
+
import type {Extent} from "ol/extent";
|
|
4
|
+
import {buffer, createEmpty, createOrUpdateFromCoordinate} from "ol/extent";
|
|
5
|
+
import Point from "ol/geom/Point";
|
|
6
|
+
|
|
7
|
+
import {isNonNullable} from "@mapsight/lib-js/nonNullable";
|
|
8
|
+
|
|
9
|
+
import getCentroidForFeatures from "../features/getCentroidForFeatures";
|
|
10
|
+
import type {Resolution} from "../index";
|
|
11
|
+
import getCentroid from "./getCentroid";
|
|
12
|
+
import getUid from "./getUid";
|
|
13
|
+
|
|
14
|
+
export type CreateClusterFeatureFunction = (
|
|
15
|
+
centroid: Coordinate,
|
|
16
|
+
features: Array<Feature>,
|
|
17
|
+
) => Array<Feature> | Feature;
|
|
18
|
+
|
|
19
|
+
const defaultCreateClusterFeature: CreateClusterFeatureFunction = (
|
|
20
|
+
centroid: Coordinate,
|
|
21
|
+
features: Array<Feature>,
|
|
22
|
+
) => {
|
|
23
|
+
const clusterFeature = new Feature(new Point(centroid));
|
|
24
|
+
clusterFeature.set("features", features);
|
|
25
|
+
return clusterFeature;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const defaultDistance = 20;
|
|
29
|
+
|
|
30
|
+
export default function cluster(
|
|
31
|
+
features: Array<Feature>,
|
|
32
|
+
resolution: Resolution,
|
|
33
|
+
getFeaturesInExtent: (extent: Extent) => Array<Feature>,
|
|
34
|
+
distance = defaultDistance,
|
|
35
|
+
createClusterFeature: CreateClusterFeatureFunction = defaultCreateClusterFeature,
|
|
36
|
+
mapFeatureToCoordinate = getCentroid,
|
|
37
|
+
): Array<Feature> {
|
|
38
|
+
if (resolution === undefined) {
|
|
39
|
+
return features;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const mapDistance = distance * resolution;
|
|
43
|
+
const extent = createEmpty();
|
|
44
|
+
const isClusteredMap: Record<string, boolean> = {};
|
|
45
|
+
const markClustered = (feature: Feature) => {
|
|
46
|
+
isClusteredMap[getUid(feature)] = true;
|
|
47
|
+
};
|
|
48
|
+
const isAlreadyClustered = (feature: Feature) =>
|
|
49
|
+
getUid(feature) in isClusteredMap;
|
|
50
|
+
const isNotAlreadyClustered = (feature: Feature) =>
|
|
51
|
+
!isAlreadyClustered(feature);
|
|
52
|
+
|
|
53
|
+
return features
|
|
54
|
+
.flatMap((feature) => {
|
|
55
|
+
if (isAlreadyClustered(feature)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const coordinate = mapFeatureToCoordinate(feature);
|
|
60
|
+
const canCluster =
|
|
61
|
+
coordinate &&
|
|
62
|
+
coordinate.length >= 2 &&
|
|
63
|
+
coordinate[0] &&
|
|
64
|
+
coordinate[1];
|
|
65
|
+
|
|
66
|
+
if (canCluster) {
|
|
67
|
+
// reuse extent to reduce object creation
|
|
68
|
+
createOrUpdateFromCoordinate(coordinate, extent);
|
|
69
|
+
buffer(extent, mapDistance, extent);
|
|
70
|
+
|
|
71
|
+
const neighbors = getFeaturesInExtent(extent).filter(
|
|
72
|
+
isNotAlreadyClustered,
|
|
73
|
+
);
|
|
74
|
+
if (neighbors.length >= 2) {
|
|
75
|
+
neighbors.forEach(markClustered);
|
|
76
|
+
return createClusterFeature(
|
|
77
|
+
getCentroidForFeatures(neighbors),
|
|
78
|
+
neighbors,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return feature;
|
|
84
|
+
})
|
|
85
|
+
.filter(isNonNullable);
|
|
86
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type {FeatureLike} from "ol/Feature";
|
|
2
|
+
import type OlMap from "ol/Map";
|
|
3
|
+
import type MapBrowserEvent from "ol/MapBrowserEvent";
|
|
4
|
+
import type Layer from "ol/layer/Layer";
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
layers?: Array<Layer>;
|
|
8
|
+
onEnter?: (feature: FeatureLike) => void;
|
|
9
|
+
onLeave?: (feature: FeatureLike) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function detectFeatureHits(map: OlMap, options: Options = {}) {
|
|
13
|
+
let previousFeature: FeatureLike | null = null;
|
|
14
|
+
|
|
15
|
+
const {layers, onEnter, onLeave} = options;
|
|
16
|
+
const layerFilter =
|
|
17
|
+
layers && layers.length
|
|
18
|
+
? (layer: Layer) => layers.indexOf(layer) > -1
|
|
19
|
+
: undefined;
|
|
20
|
+
|
|
21
|
+
function onFeatureHit(feature: FeatureLike, layer: Layer) {
|
|
22
|
+
if (!layer || feature === previousFeature) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (previousFeature) {
|
|
27
|
+
onLeave?.(previousFeature);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
previousFeature = feature;
|
|
31
|
+
onEnter?.(feature);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function onPointerMove(e: MapBrowserEvent) {
|
|
35
|
+
if (e.dragging) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const pixel = map.getEventPixel(e.originalEvent);
|
|
39
|
+
|
|
40
|
+
let foundFeature = false;
|
|
41
|
+
map.forEachFeatureAtPixel(
|
|
42
|
+
pixel,
|
|
43
|
+
(feature, layer) => {
|
|
44
|
+
foundFeature = true;
|
|
45
|
+
onFeatureHit(feature, layer);
|
|
46
|
+
},
|
|
47
|
+
{layerFilter: layerFilter},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (!foundFeature && previousFeature) {
|
|
51
|
+
onLeave?.(previousFeature);
|
|
52
|
+
previousFeature = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
map.on("pointermove", onPointerMove);
|
|
57
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type Feature from "ol/Feature";
|
|
2
|
+
import Point from "ol/geom/Point";
|
|
3
|
+
|
|
4
|
+
import getExtentCentroid from "../extent/getCentroid";
|
|
5
|
+
|
|
6
|
+
export default function getCentroid(feature: Feature) {
|
|
7
|
+
const geometry = feature.getGeometry();
|
|
8
|
+
|
|
9
|
+
if (!geometry) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (geometry instanceof Point) {
|
|
14
|
+
return geometry.getCoordinates();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return getExtentCentroid(geometry.getExtent());
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type Feature from "ol/Feature";
|
|
2
|
+
import type OlMap from "ol/Map";
|
|
3
|
+
import type BaseLayer from "ol/layer/Base";
|
|
4
|
+
import LayerGroup from "ol/layer/Group";
|
|
5
|
+
import Layer from "ol/layer/Layer";
|
|
6
|
+
import type Source from "ol/source/Source";
|
|
7
|
+
import type VectorFeatureSource from "ol/source/Vector";
|
|
8
|
+
|
|
9
|
+
export default function getLayer(map: OlMap, feature: Feature) {
|
|
10
|
+
let featureLayer: null | Layer = null;
|
|
11
|
+
|
|
12
|
+
function checkLayerForFeature(layer: BaseLayer): boolean {
|
|
13
|
+
if (layer instanceof LayerGroup) {
|
|
14
|
+
return layer.getLayers().getArray().some(checkLayerForFeature);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (layer instanceof Layer) {
|
|
18
|
+
const source = layer.getSource() as
|
|
19
|
+
| VectorFeatureSource
|
|
20
|
+
| Source
|
|
21
|
+
| null;
|
|
22
|
+
|
|
23
|
+
if (
|
|
24
|
+
source &&
|
|
25
|
+
"getFeatures" in source &&
|
|
26
|
+
source.getFeatures().some((a) => a === feature)
|
|
27
|
+
) {
|
|
28
|
+
featureLayer = layer;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
map.getLayers().getArray().some(checkLayerForFeature);
|
|
37
|
+
|
|
38
|
+
return featureLayer;
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Feature from "ol/Feature";
|
|
2
|
+
|
|
3
|
+
import * as nonNull from "@mapsight/lib-js/nonNullable";
|
|
4
|
+
|
|
5
|
+
import middleCoordinate from "../coordinates/middleCoordinate";
|
|
6
|
+
import getCentroid from "../feature/getCentroid";
|
|
7
|
+
|
|
8
|
+
export default function getCentroidForFeatures(features: Array<Feature>) {
|
|
9
|
+
return middleCoordinate(features.map(getCentroid).filter(nonNull.is));
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Feature from "ol/Feature";
|
|
2
|
+
|
|
3
|
+
import * as nonNull from "@mapsight/lib-js/nonNullable";
|
|
4
|
+
|
|
5
|
+
import combineExtents from "../extents/combineExtents";
|
|
6
|
+
import getExtent from "../feature/getExtent";
|
|
7
|
+
|
|
8
|
+
export default function getExtentForFeatures(features: Array<Feature>) {
|
|
9
|
+
return combineExtents(features.map(getExtent).filter(nonNull.is));
|
|
10
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type {Type as GeometryType} from "ol/geom/Geometry";
|
|
2
|
+
import type Geometry from "ol/geom/Geometry";
|
|
3
|
+
import LineString from "ol/geom/LineString";
|
|
4
|
+
import Point from "ol/geom/Point";
|
|
5
|
+
import Polygon from "ol/geom/Polygon";
|
|
6
|
+
|
|
7
|
+
import type {INTERMEDIATE_FILTER, RING_FILTER, VERTICES_FILTER} from "../index";
|
|
8
|
+
import getLSSegmentVertices from "./getLineStringSegmentVerticesWithRotation";
|
|
9
|
+
import getPolygonSegmentVertices from "./getPolygonRingSegmentVerticesWithRotation";
|
|
10
|
+
|
|
11
|
+
export type GeometryWithMeta = [Geometry, {rotation?: number}];
|
|
12
|
+
|
|
13
|
+
const deriveLSVertexGeometries = (
|
|
14
|
+
b: LineString,
|
|
15
|
+
v?: VERTICES_FILTER,
|
|
16
|
+
i?: INTERMEDIATE_FILTER,
|
|
17
|
+
) =>
|
|
18
|
+
getLSSegmentVertices(b, v, i).map(
|
|
19
|
+
([c, r]): GeometryWithMeta => [new Point(c), {rotation: r}],
|
|
20
|
+
);
|
|
21
|
+
const derivePolygonVertexGeometries = (
|
|
22
|
+
b: Polygon,
|
|
23
|
+
v?: VERTICES_FILTER,
|
|
24
|
+
i?: INTERMEDIATE_FILTER,
|
|
25
|
+
j?: RING_FILTER,
|
|
26
|
+
) =>
|
|
27
|
+
getPolygonSegmentVertices(b, v, i, j).map(
|
|
28
|
+
([c, r]): GeometryWithMeta => [new Point(c), {rotation: r}],
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export type Derivation =
|
|
32
|
+
| "vertex"
|
|
33
|
+
| "vertices"
|
|
34
|
+
| "firstVertex"
|
|
35
|
+
| "firstVertices"
|
|
36
|
+
| "lastVertex"
|
|
37
|
+
| "lastVertices"
|
|
38
|
+
| "segmentStart"
|
|
39
|
+
| "segmentStarts"
|
|
40
|
+
| "intermediateSegmentStart"
|
|
41
|
+
| "intermediateSegmentStarts"
|
|
42
|
+
| "segmentEnd"
|
|
43
|
+
| "segmentEnds"
|
|
44
|
+
| "intermediateSegmentEnd"
|
|
45
|
+
| "intermediateSegmentEnds";
|
|
46
|
+
|
|
47
|
+
export default function deriveGeometriesFromBase(
|
|
48
|
+
base: Geometry,
|
|
49
|
+
derivation: Derivation | GeometryType | null = null,
|
|
50
|
+
): Array<GeometryWithMeta> {
|
|
51
|
+
// early return for common case
|
|
52
|
+
if (derivation === null) {
|
|
53
|
+
return [[base, {}]];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (base instanceof LineString) {
|
|
57
|
+
switch (derivation) {
|
|
58
|
+
case "vertex":
|
|
59
|
+
case "vertices":
|
|
60
|
+
return deriveLSVertexGeometries(base);
|
|
61
|
+
case "firstVertex":
|
|
62
|
+
case "firstVertices":
|
|
63
|
+
return deriveLSVertexGeometries(base, "first");
|
|
64
|
+
case "lastVertex":
|
|
65
|
+
case "lastVertices":
|
|
66
|
+
return deriveLSVertexGeometries(base, "last");
|
|
67
|
+
case "segmentStart":
|
|
68
|
+
case "segmentStarts":
|
|
69
|
+
return deriveLSVertexGeometries(base, "start");
|
|
70
|
+
case "intermediateSegmentStart":
|
|
71
|
+
case "intermediateSegmentStarts":
|
|
72
|
+
return deriveLSVertexGeometries(base, "start", "intermediate");
|
|
73
|
+
case "segmentEnd":
|
|
74
|
+
case "segmentEnds":
|
|
75
|
+
return deriveLSVertexGeometries(base, "end");
|
|
76
|
+
case "intermediateSegmentEnd":
|
|
77
|
+
case "intermediateSegmentEnds":
|
|
78
|
+
return deriveLSVertexGeometries(base, "end", "intermediate");
|
|
79
|
+
default:
|
|
80
|
+
}
|
|
81
|
+
} else if (base instanceof Polygon) {
|
|
82
|
+
// TODO: discriminate outer and inner ring
|
|
83
|
+
switch (derivation) {
|
|
84
|
+
case "vertex":
|
|
85
|
+
case "vertices":
|
|
86
|
+
return derivePolygonVertexGeometries(base);
|
|
87
|
+
case "firstVertex":
|
|
88
|
+
case "firstVertices":
|
|
89
|
+
return derivePolygonVertexGeometries(base, "first");
|
|
90
|
+
case "lastVertex":
|
|
91
|
+
case "lastVertices":
|
|
92
|
+
return derivePolygonVertexGeometries(base, "last");
|
|
93
|
+
case "segmentStart":
|
|
94
|
+
case "segmentStarts":
|
|
95
|
+
return derivePolygonVertexGeometries(base, "start");
|
|
96
|
+
case "intermediateSegmentStart":
|
|
97
|
+
case "intermediateSegmentStarts":
|
|
98
|
+
return derivePolygonVertexGeometries(
|
|
99
|
+
base,
|
|
100
|
+
"start",
|
|
101
|
+
"intermediate",
|
|
102
|
+
);
|
|
103
|
+
case "segmentEnd":
|
|
104
|
+
case "segmentEnds":
|
|
105
|
+
return derivePolygonVertexGeometries(base, "end");
|
|
106
|
+
case "intermediateSegmentEnd":
|
|
107
|
+
case "intermediateSegmentEnds":
|
|
108
|
+
return derivePolygonVertexGeometries(
|
|
109
|
+
base,
|
|
110
|
+
"end",
|
|
111
|
+
"intermediate",
|
|
112
|
+
);
|
|
113
|
+
default:
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.error(
|
|
118
|
+
"Could not derive " + derivation + " from base geometry " + base,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return [[base, {}]];
|
|
122
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type {Type as GeometryType} from "ol/geom/Geometry";
|
|
2
|
+
import type Geometry from "ol/geom/Geometry";
|
|
3
|
+
import GeometryCollection from "ol/geom/GeometryCollection";
|
|
4
|
+
|
|
5
|
+
import {isNonNullable} from "@mapsight/lib-js/nonNullable";
|
|
6
|
+
|
|
7
|
+
const GEOMETRY_TYPE_DOMINANCE: Record<GeometryType, number> = {
|
|
8
|
+
GeometryCollection: 0,
|
|
9
|
+
Circle: 1,
|
|
10
|
+
Point: 1,
|
|
11
|
+
LineString: 2,
|
|
12
|
+
LinearRing: 2,
|
|
13
|
+
MultiPoint: 2,
|
|
14
|
+
Polygon: 3,
|
|
15
|
+
MultiLineString: 3,
|
|
16
|
+
MultiPolygon: 4,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function getGeometryTypeDominance(geometryType: GeometryType) {
|
|
20
|
+
return GEOMETRY_TYPE_DOMINANCE[geometryType] ?? 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function getDominantGeometryType(
|
|
24
|
+
geometry: Geometry,
|
|
25
|
+
): undefined | GeometryType {
|
|
26
|
+
if (geometry instanceof GeometryCollection) {
|
|
27
|
+
const types = geometry
|
|
28
|
+
.getGeometries()
|
|
29
|
+
.map(getDominantGeometryType)
|
|
30
|
+
.filter(isNonNullable);
|
|
31
|
+
types.sort(
|
|
32
|
+
(a, b) =>
|
|
33
|
+
// TODO: use compare helper
|
|
34
|
+
getGeometryTypeDominance(b) - getGeometryTypeDominance(a),
|
|
35
|
+
);
|
|
36
|
+
return types[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return geometry.getType();
|
|
40
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type LineString from "ol/geom/LineString";
|
|
2
|
+
|
|
3
|
+
import {ensureNonNullable} from "@mapsight/lib-js/nonNullable";
|
|
4
|
+
|
|
5
|
+
import equals from "../coordinates/equals";
|
|
6
|
+
import type {INTERMEDIATE_FILTER, VERTICES_FILTER, Vertex} from "../index";
|
|
7
|
+
|
|
8
|
+
export default function getLineStringSegmentVerticesWithRotation(
|
|
9
|
+
lineStringGeometry: LineString,
|
|
10
|
+
verticesFilter: VERTICES_FILTER = "all",
|
|
11
|
+
intermediateFilter: INTERMEDIATE_FILTER = "all",
|
|
12
|
+
) {
|
|
13
|
+
const verticesWithRotation: Array<Vertex> = [];
|
|
14
|
+
const first = lineStringGeometry.getFirstCoordinate();
|
|
15
|
+
const last = lineStringGeometry.getLastCoordinate();
|
|
16
|
+
|
|
17
|
+
lineStringGeometry.forEachSegment(function processSegment(start, end) {
|
|
18
|
+
const dx = ensureNonNullable(end[0]) - ensureNonNullable(start[0]);
|
|
19
|
+
const dy = ensureNonNullable(end[1]) - ensureNonNullable(start[1]);
|
|
20
|
+
const rotation = -Math.round(Math.atan2(dy, dx) * 100) / 100;
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
verticesFilter === "first"
|
|
24
|
+
? equals(start, first)
|
|
25
|
+
: (verticesFilter === "start" || verticesFilter === "all") &&
|
|
26
|
+
!(
|
|
27
|
+
intermediateFilter === "intermediate" &&
|
|
28
|
+
equals(start, first)
|
|
29
|
+
)
|
|
30
|
+
) {
|
|
31
|
+
verticesWithRotation.push([[...start], rotation]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
verticesFilter === "last"
|
|
36
|
+
? equals(end, last)
|
|
37
|
+
: (verticesFilter === "end" || verticesFilter === "all") &&
|
|
38
|
+
!(
|
|
39
|
+
intermediateFilter === "intermediate" &&
|
|
40
|
+
equals(end, last)
|
|
41
|
+
)
|
|
42
|
+
) {
|
|
43
|
+
verticesWithRotation.push([[...end], rotation]);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return verticesWithRotation;
|
|
48
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type LinearRing from "ol/geom/LinearRing";
|
|
2
|
+
import type Polygon from "ol/geom/Polygon";
|
|
3
|
+
|
|
4
|
+
import {ensureNonNullable} from "@mapsight/lib-js/nonNullable";
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
INTERMEDIATE_FILTER,
|
|
8
|
+
RING_FILTER,
|
|
9
|
+
VERTICES_FILTER,
|
|
10
|
+
Vertex,
|
|
11
|
+
} from "../index";
|
|
12
|
+
|
|
13
|
+
function getLinearRingSegmentVerticesWithRotation(
|
|
14
|
+
linearRing: LinearRing,
|
|
15
|
+
verticesFilter: VERTICES_FILTER,
|
|
16
|
+
intermediateFilter: INTERMEDIATE_FILTER,
|
|
17
|
+
) {
|
|
18
|
+
const verticesWithRotation: Array<Vertex> = [];
|
|
19
|
+
const ringCoords = linearRing.getCoordinates();
|
|
20
|
+
|
|
21
|
+
ringCoords.forEach((start, i) => {
|
|
22
|
+
const end = ringCoords[i + 1];
|
|
23
|
+
if (!end) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const isFirst = i === 0;
|
|
28
|
+
const isLast = ringCoords[i + 2] === undefined;
|
|
29
|
+
|
|
30
|
+
const dx = ensureNonNullable(end[0]) - ensureNonNullable(start[0]);
|
|
31
|
+
const dy = ensureNonNullable(end[1]) - ensureNonNullable(start[1]);
|
|
32
|
+
const rotation = -Math.round(Math.atan2(dy, dx) * 100) / 100;
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
verticesFilter === "first"
|
|
36
|
+
? isFirst
|
|
37
|
+
: (verticesFilter === "start" || verticesFilter === "all") &&
|
|
38
|
+
!(intermediateFilter === "intermediate" && isFirst)
|
|
39
|
+
) {
|
|
40
|
+
verticesWithRotation.push([[...start], rotation]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
verticesFilter === "last"
|
|
45
|
+
? isLast
|
|
46
|
+
: (verticesFilter === "end" || verticesFilter === "all") &&
|
|
47
|
+
!(intermediateFilter === "intermediate" && isLast)
|
|
48
|
+
) {
|
|
49
|
+
verticesWithRotation.push([[...end], rotation]);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return verticesWithRotation;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default function getPolygonRingSegmentVerticesWithRotation(
|
|
57
|
+
polygonGeometry: Polygon,
|
|
58
|
+
verticesFilter: VERTICES_FILTER = "all",
|
|
59
|
+
intermediateFilter: INTERMEDIATE_FILTER = "all",
|
|
60
|
+
ringFilter: RING_FILTER = "all",
|
|
61
|
+
) {
|
|
62
|
+
let verticesWithRotation: Array<Vertex> = [];
|
|
63
|
+
|
|
64
|
+
if (ringFilter === "all" || ringFilter === "outer") {
|
|
65
|
+
const outerRing = polygonGeometry.getLinearRing(0);
|
|
66
|
+
if (outerRing) {
|
|
67
|
+
verticesWithRotation = getLinearRingSegmentVerticesWithRotation(
|
|
68
|
+
outerRing,
|
|
69
|
+
verticesFilter,
|
|
70
|
+
intermediateFilter,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (ringFilter === "all" || ringFilter === "inner") {
|
|
76
|
+
const innerRing = polygonGeometry.getLinearRing(1);
|
|
77
|
+
if (innerRing) {
|
|
78
|
+
verticesWithRotation = [
|
|
79
|
+
...verticesWithRotation,
|
|
80
|
+
...getLinearRingSegmentVerticesWithRotation(
|
|
81
|
+
innerRing,
|
|
82
|
+
verticesFilter,
|
|
83
|
+
intermediateFilter,
|
|
84
|
+
),
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return verticesWithRotation;
|
|
90
|
+
}
|