@mapcomponents/react-maplibre 0.1.61 → 0.1.62
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/CHANGELOG.md +5 -0
- package/coverage/clover.xml +36 -48
- package/coverage/coverage-final.json +3 -3
- package/coverage/lcov-report/index.html +23 -23
- package/coverage/lcov-report/src/components/MapLibreMap/MapLibreMap.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MapLibreMap/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCenterPosition/MlCenterPosition.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlCenterPosition/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/MlCreatePdfButton.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfButton/index.html +1 -1
- package/coverage/lcov-report/src/components/MlCreatePdfForm/MlCreatePdfForm.tsx.html +2 -8
- package/coverage/lcov-report/src/components/MlCreatePdfForm/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/MlFeatureEditor.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlFeatureEditor/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/MlFillExtrusionLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlFillExtrusionLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlFollowGps/MlFollowGps.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlFollowGps/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/MlGPXViewer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/gpxConverter.js.html +1 -1
- package/coverage/lcov-report/src/components/MlGPXViewer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/MlGeoJsonLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeoJsonLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlGeojsonLayerWithSource/MlGeojsonLayerWithSource.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlGeojsonLayerWithSource/index.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/MlImageMarkerLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlImageMarkerLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/MlLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerMagnify/MlLayerMagnify.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerMagnify/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwipe/MlLayerSwipe.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwipe/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/MlLayerSwitcher.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/LayerBox.js.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/components/index.html +1 -1
- package/coverage/lcov-report/src/components/MlLayerSwitcher/index.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/MlMarker.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlMarker/index.html +1 -1
- package/coverage/lcov-report/src/components/MlMeasureTool/MlMeasureTool.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlMeasureTool/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/MlNavigationCompass.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationCompass/index.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/MlNavigationTools.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlNavigationTools/index.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/MlOsmLayer.stories_.js.html +1 -1
- package/coverage/lcov-report/src/components/MlOsmLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlScaleReference/MlScaleReference.js.html +1 -1
- package/coverage/lcov-report/src/components/MlScaleReference/index.html +1 -1
- package/coverage/lcov-report/src/components/MlShareMapState/MlShareMapState.js.html +1 -1
- package/coverage/lcov-report/src/components/MlShareMapState/index.html +1 -1
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/MlSpatialElevationProfile.js.html +1 -1
- package/coverage/lcov-report/src/components/MlSpatialElevationProfile/index.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/MlThreeJsLayer.js.html +1 -1
- package/coverage/lcov-report/src/components/MlThreeJsLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/MlTransitionGeoJsonLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlTransitionGeoJsonLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/MlUseMapDebugger.js.html +1 -1
- package/coverage/lcov-report/src/components/MlUseMapDebugger/index.html +1 -1
- package/coverage/lcov-report/src/components/MlVectorTileLayer/MlVectorTileLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlVectorTileLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/MlWmsFeatureInfoPopup.js.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsFeatureInfoPopup/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLayer/MlWmsLayer.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLayer/index.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLoader/MlWmsLoader.tsx.html +1 -1
- package/coverage/lcov-report/src/components/MlWmsLoader/index.html +1 -1
- package/coverage/lcov-report/src/contexts/MapContext.tsx.html +1 -1
- package/coverage/lcov-report/src/contexts/SimpleDataContext.js.html +1 -1
- package/coverage/lcov-report/src/contexts/SimpleDataProvider.js.html +1 -1
- package/coverage/lcov-report/src/contexts/index.html +1 -1
- package/coverage/lcov-report/src/hooks/index.html +11 -11
- package/coverage/lcov-report/src/hooks/useCameraFollowPath/index.html +1 -1
- package/coverage/lcov-report/src/hooks/useCameraFollowPath/useCameraFollowPath.tsx.html +1 -1
- package/coverage/lcov-report/src/hooks/useExportMap/index.html +14 -14
- package/coverage/lcov-report/src/hooks/useExportMap/index.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useExportMap/lib.ts.html +21 -108
- package/coverage/lcov-report/src/hooks/useLayer.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useLayerEvent.js.html +9 -9
- package/coverage/lcov-report/src/hooks/useMap.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useMapState.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useSource.ts.html +1 -1
- package/coverage/lcov-report/src/hooks/useWms.js.html +1 -1
- package/coverage/lcov-report/src/index.html +1 -1
- package/coverage/lcov-report/src/index.ts.html +5 -2
- package/coverage/lcov.info +50 -72
- package/dist/components/MlCreatePdfForm/MlCreatePdfForm.stories.d.ts +1 -0
- package/dist/components/MlCreatePdfForm/lib/PdfContext.d.ts +3 -16
- package/dist/components/MlCreatePdfForm/lib/PdfPreview.d.ts +19 -6
- package/dist/components/MlCreatePdfForm/lib/_PdfPreview.d.ts +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +505 -597
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -1
- package/src/components/MlCreatePdfForm/MlCreatePdfForm.stories.tsx +16 -1
- package/src/components/MlCreatePdfForm/MlCreatePdfForm.tsx +0 -2
- package/src/components/MlCreatePdfForm/lib/PdfContext.tsx +16 -18
- package/src/components/MlCreatePdfForm/lib/PdfForm.tsx +78 -5
- package/src/components/MlCreatePdfForm/lib/PdfPreview.tsx +285 -357
- package/src/components/MlCreatePdfForm/lib/_PdfPreview.tsx +399 -0
- package/src/components/MlCreatePdfForm/lib/pdfContext.d.ts +24 -0
- package/src/components/MlCreatePdfForm/lib/preview.css +114 -0
- package/src/hooks/useExportMap/lib.ts +14 -43
- package/src/index.ts +1 -0
|
@@ -1,399 +1,327 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import React, { useRef, useEffect, useMemo } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import Moveable from 'react-moveable';
|
|
4
4
|
import useMap from '../../../hooks/useMap';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const createPreviewGeojson = (
|
|
11
|
-
geojsonProps: { center: LngLat; distance: number; bearing: number },
|
|
12
|
-
orientation: string
|
|
13
|
-
) => {
|
|
14
|
-
const topLeftAngle = orientation === 'portrait' ? -35.3 : -54.7;
|
|
15
|
-
const bottomRightAngle = orientation === 'portrait' ? 144.7 : 125.3;
|
|
16
|
-
const topLeft = turf.destination(
|
|
17
|
-
[geojsonProps.center.lng, geojsonProps.center.lat],
|
|
18
|
-
geojsonProps.distance,
|
|
19
|
-
topLeftAngle
|
|
20
|
-
);
|
|
21
|
-
const bottomRight = turf.destination(
|
|
22
|
-
[geojsonProps.center.lng, geojsonProps.center.lat],
|
|
23
|
-
geojsonProps.distance,
|
|
24
|
-
bottomRightAngle
|
|
25
|
-
);
|
|
26
|
-
const bbox = [
|
|
27
|
-
topLeft.geometry.coordinates[0],
|
|
28
|
-
topLeft.geometry.coordinates[1],
|
|
29
|
-
bottomRight.geometry.coordinates[0],
|
|
30
|
-
bottomRight.geometry.coordinates[1],
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
let _previewGeojson = turf.bboxPolygon(bbox as BBox);
|
|
34
|
-
_previewGeojson = turf.transformRotate(_previewGeojson, geojsonProps.bearing);
|
|
35
|
-
if (!_previewGeojson?.properties) {
|
|
36
|
-
_previewGeojson.properties = {};
|
|
37
|
-
}
|
|
38
|
-
_previewGeojson.properties.bearing = geojsonProps.bearing;
|
|
39
|
-
return _previewGeojson;
|
|
40
|
-
};
|
|
5
|
+
import useMapState from '../../../hooks/useMapState';
|
|
6
|
+
import * as turf from '@turf/turf';
|
|
7
|
+
import { PdfPreviewOptions } from './pdfContext';
|
|
8
|
+
import { LngLatLike, Map as MapType, PointLike } from 'maplibre-gl';
|
|
9
|
+
import { Feature, Units } from '@turf/turf';
|
|
41
10
|
|
|
42
|
-
|
|
11
|
+
type Props = {
|
|
43
12
|
/**
|
|
44
13
|
* Id of the target MapLibre instance in mapContext
|
|
45
14
|
*/
|
|
46
15
|
mapId?: string;
|
|
47
16
|
/**
|
|
48
|
-
*
|
|
49
|
-
* This layer will be visually beneath the layer with the "insertBeforeLayer" id.
|
|
17
|
+
* Polygon GeoJson Feature representing the printing area
|
|
50
18
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
19
|
+
geojsonRef: React.MutableRefObject<
|
|
20
|
+
| Feature
|
|
21
|
+
| undefined
|
|
22
|
+
>;
|
|
23
|
+
/**
|
|
24
|
+
* a state variable containing the PDF previews current state
|
|
25
|
+
*/
|
|
26
|
+
options: PdfPreviewOptions;
|
|
27
|
+
/**
|
|
28
|
+
* setter function to update the current PDF preview state
|
|
29
|
+
*/
|
|
30
|
+
setOptions: (arg1: (val: PdfPreviewOptions) => PdfPreviewOptions) => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function getTargetRotationAngle(target: HTMLDivElement) {
|
|
34
|
+
const el_style = window.getComputedStyle(target, null);
|
|
35
|
+
const el_transform = el_style.getPropertyValue('transform');
|
|
36
|
+
|
|
37
|
+
let deg = 0;
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
39
|
+
if (el_transform !== 'none') {
|
|
40
|
+
const values = el_transform.split('(')[1].split(')')[0].split(',');
|
|
41
|
+
const a = parseFloat(values[0]);
|
|
42
|
+
const b = parseFloat(values[1]);
|
|
43
|
+
deg = Math.round(Math.atan2(b, a) * (180 / Math.PI));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return deg < 0 ? deg + 360 : deg;
|
|
59
47
|
}
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
function calcElemTransformedPoint(
|
|
50
|
+
el: HTMLDivElement,
|
|
51
|
+
point: [number, number],
|
|
52
|
+
transformOrigin: [number, number]
|
|
53
|
+
): PointLike {
|
|
54
|
+
const style = getComputedStyle(el);
|
|
55
|
+
const p = [point[0] - transformOrigin[0], point[1] - transformOrigin[1]];
|
|
65
56
|
|
|
66
|
-
const
|
|
57
|
+
const matrix = new DOMMatrixReadOnly(style.transform);
|
|
67
58
|
|
|
68
|
-
|
|
59
|
+
// transform pixel coordinates according to the css transform state of "el" (target)
|
|
60
|
+
return [
|
|
61
|
+
p[0] * matrix.a + p[1] * matrix.c + matrix.e + transformOrigin[0],
|
|
62
|
+
p[0] * matrix.b + p[1] * matrix.d + matrix.f + transformOrigin[1],
|
|
63
|
+
];
|
|
64
|
+
}
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
// measure distance in pixels that is used to determine the current css transform.scale relative to the maps viewport.zoom
|
|
67
|
+
const scaleAnchorInPixels = 10;
|
|
71
68
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
// used to determine the MapZoomScale modifier which is multiplied with props.options.scale to relate the scale to the current map viewport.zoom
|
|
70
|
+
function getMapZoomScaleModifier(point: [number, number], _map: MapType) {
|
|
71
|
+
const left = _map.unproject(point);
|
|
72
|
+
const right = _map.unproject([point[0] + scaleAnchorInPixels, point[1]]);
|
|
73
|
+
const maxMeters = left.distanceTo(right);
|
|
74
|
+
return scaleAnchorInPixels / maxMeters;
|
|
75
|
+
}
|
|
78
76
|
|
|
77
|
+
/**
|
|
78
|
+
* PdfPreview component renders a transformable (drag, scale, rotate) preview of the desired export or print content
|
|
79
|
+
*/
|
|
80
|
+
export default function PdfPreview(props: Props) {
|
|
81
|
+
const mapState = useMapState({ mapId: props.mapId, watch: { layers: false, viewport: true } });
|
|
82
|
+
const targetRef = useRef<HTMLDivElement>(null);
|
|
83
|
+
const fixedScaleRef = useRef<number | undefined>();
|
|
84
|
+
const moveableRef = useRef<Moveable>(null);
|
|
85
|
+
const mapContainerRef = useRef<HTMLDivElement>(document.querySelector('.mapContainer'));
|
|
86
|
+
//const [transform, setTransform] = useState('translate(452.111px, 15.6148px)');
|
|
79
87
|
const mapHook = useMap({
|
|
80
88
|
mapId: props.mapId,
|
|
81
|
-
waitForLayer: props.insertBeforeLayer,
|
|
82
89
|
});
|
|
83
90
|
|
|
84
91
|
useEffect(() => {
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
if (!mapState?.viewport?.zoom || !mapHook.map) return;
|
|
93
|
+
// if the component was initialized with scale or center as undefined derive those values from the current map view state
|
|
94
|
+
|
|
95
|
+
//initialize props if not defined
|
|
96
|
+
const _centerX = Math.round(mapHook.map.map._container.clientWidth / 2);
|
|
97
|
+
const _centerY = Math.round(mapHook.map.map._container.clientHeight / 2);
|
|
98
|
+
|
|
99
|
+
if (!props.options.scale) {
|
|
100
|
+
//const scale = parseFloat(/(14/mapState.viewport.zoom));
|
|
101
|
+
const scale = 1 / getMapZoomScaleModifier([_centerX, _centerY], mapHook.map.map);
|
|
102
|
+
|
|
103
|
+
props.setOptions((val: PdfPreviewOptions) => ({ ...val, scale: [scale, scale] }));
|
|
104
|
+
}
|
|
105
|
+
if (!props.options.center) {
|
|
106
|
+
const _center = mapHook.map.map.unproject([_centerX, _centerY]);
|
|
107
|
+
props.setOptions((val: PdfPreviewOptions) => ({
|
|
108
|
+
...val,
|
|
109
|
+
center: [_center.lng, _center.lat],
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
}, [mapHook.map, mapState.viewport?.zoom]);
|
|
103
113
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Math.floor(canvasHeight / 2 - bboxPixelHeight / 2),
|
|
107
|
-
]);
|
|
108
|
-
|
|
109
|
-
const distance = turf.distance([center.lng, center.lat], [topLeft.lng, topLeft.lat]);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (!mapHook.map) return;
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
mapHook.map.map.setPitch(0);
|
|
118
|
+
const _maxPitch = mapHook.map.map.getMaxPitch();
|
|
119
|
+
mapHook.map.map.setMaxPitch(0);
|
|
120
|
+
return () => {
|
|
121
|
+
mapHook.map?.map.setMaxPitch(_maxPitch);
|
|
116
122
|
};
|
|
117
|
-
setGeojsonProps(tmpGeojsonProps);
|
|
118
|
-
pdfContext.geojsonRef.current = tmpGeojsonProps.geojson;
|
|
119
123
|
}, [mapHook.map]);
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}, [pdfContext.orientation]);
|
|
129
|
-
|
|
130
|
-
// Resize handle events
|
|
131
|
-
useLayerEvent({
|
|
132
|
-
event: 'mouseenter',
|
|
133
|
-
layerId: 'pdfPreviewGeojsonResizeHandle',
|
|
134
|
-
eventHandler: function () {
|
|
135
|
-
if (!mapHook.map) return;
|
|
136
|
-
|
|
137
|
-
mapHook.map.map._canvas.style.cursor = 'nwse-resize';
|
|
138
|
-
mapHook.map.map.dragPan.disable();
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
useLayerEvent({
|
|
142
|
-
event: 'mouseleave',
|
|
143
|
-
layerId: 'pdfPreviewGeojsonResizeHandle',
|
|
144
|
-
eventHandler: function () {
|
|
145
|
-
if (!mapHook.map) return;
|
|
146
|
-
|
|
147
|
-
mapHook.map.map._canvas.style.cursor = '';
|
|
148
|
-
mapHook.map.map.dragPan.enable();
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
useLayerEvent({
|
|
152
|
-
event: 'mousedown',
|
|
153
|
-
layerId: 'pdfPreviewGeojsonResizeHandle',
|
|
154
|
-
addTouchEvents: true,
|
|
155
|
-
eventHandler: function (e: MapMouseEvent | MapTouchEvent) {
|
|
156
|
-
e.preventDefault();
|
|
157
|
-
if (!mapHook.map) return;
|
|
158
|
-
|
|
159
|
-
dragging.current = false;
|
|
160
|
-
draggingRotationHandle.current = false;
|
|
161
|
-
draggingResizeHandle.current = true;
|
|
162
|
-
mapHook.map.map._canvas.style.cursor = 'move';
|
|
163
|
-
|
|
164
|
-
function onMove(e: MapMouseEvent | MapTouchEvent) {
|
|
165
|
-
if (!pdfContext.geojsonRef || !draggingResizeHandle.current || !pdfContext.orientation)
|
|
166
|
-
return;
|
|
167
|
-
|
|
168
|
-
const tmpGeojsonProps = JSON.parse(JSON.stringify(geojsonProps));
|
|
169
|
-
let _distance = turf.distance(
|
|
170
|
-
[tmpGeojsonProps.center.lng, tmpGeojsonProps.center.lat],
|
|
171
|
-
[e.lngLat.lng, e.lngLat.lat]
|
|
172
|
-
);
|
|
173
|
-
// limit max diagonal distance of PDF area to 120km as larger area lead to distortions for northern and southern areas
|
|
174
|
-
if (_distance > 60) {
|
|
175
|
-
_distance = 60;
|
|
176
|
-
}
|
|
177
|
-
tmpGeojsonProps.distance = _distance;
|
|
178
|
-
tmpGeojsonProps.geojson = createPreviewGeojson(tmpGeojsonProps, pdfContext.orientation);
|
|
179
|
-
pdfContext.geojsonRef.current = tmpGeojsonProps.geojson;
|
|
180
|
-
setGeojsonProps(tmpGeojsonProps);
|
|
181
|
-
}
|
|
182
|
-
function onUp() {
|
|
183
|
-
if (!draggingResizeHandle.current || !mapHook.map) return;
|
|
125
|
+
const transformOrigin = useMemo<[number, number]>(() => {
|
|
126
|
+
if (props.options.orientation === 'portrait') {
|
|
127
|
+
return [props.options.width / 2, props.options.height / 2];
|
|
128
|
+
} else {
|
|
129
|
+
return [props.options.height / 2, props.options.width / 2];
|
|
130
|
+
}
|
|
131
|
+
}, [props.options.orientation, props.options.width, props.options.height]);
|
|
184
132
|
|
|
185
|
-
|
|
186
|
-
|
|
133
|
+
const transform = useMemo(() => {
|
|
134
|
+
if (!mapHook.map || !props.options.scale) return 'none';
|
|
187
135
|
|
|
188
|
-
|
|
189
|
-
// Unbind mouse events
|
|
190
|
-
mapHook.map.map.off('mousemove', onMove);
|
|
191
|
-
mapHook.map.map.off('touchmove', onMove);
|
|
192
|
-
}
|
|
136
|
+
const centerInPixels = mapHook.map.map.project(props.options.center as LngLatLike);
|
|
193
137
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
mapHook.map.map.once('mouseup', onUp);
|
|
198
|
-
mapHook.map.map.once('touchend', onUp);
|
|
199
|
-
},
|
|
200
|
-
});
|
|
138
|
+
const x = centerInPixels.x;
|
|
139
|
+
const y = centerInPixels.y;
|
|
140
|
+
const scale = props.options.scale[0] * getMapZoomScaleModifier([x, y], mapHook.map.map);
|
|
201
141
|
|
|
202
|
-
|
|
203
|
-
useLayerEvent({
|
|
204
|
-
event: 'mouseenter',
|
|
205
|
-
layerId: 'pdfPreviewGeojsonRotationHandle',
|
|
206
|
-
eventHandler: function () {
|
|
207
|
-
if (!mapHook.map) return;
|
|
142
|
+
const viewportBearing = mapState?.viewport?.bearing ? mapState.viewport?.bearing : 0;
|
|
208
143
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
event: 'mouseleave',
|
|
215
|
-
layerId: 'pdfPreviewGeojsonRotationHandle',
|
|
216
|
-
eventHandler: function () {
|
|
217
|
-
if (!mapHook.map) return;
|
|
218
|
-
|
|
219
|
-
mapHook.map.map._canvas.style.cursor = '';
|
|
220
|
-
mapHook.map.map.dragPan.enable();
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
useLayerEvent({
|
|
224
|
-
event: 'mousedown',
|
|
225
|
-
layerId: 'pdfPreviewGeojsonRotationHandle',
|
|
226
|
-
addTouchEvents: true,
|
|
227
|
-
eventHandler: function (e: MapMouseEvent | MapTouchEvent) {
|
|
228
|
-
e.preventDefault();
|
|
229
|
-
if (!mapHook.map || !pdfContext.orientation) return;
|
|
230
|
-
|
|
231
|
-
dragging.current = false;
|
|
232
|
-
draggingResizeHandle.current = false;
|
|
233
|
-
draggingRotationHandle.current = true;
|
|
234
|
-
mapHook.map.map._canvas.style.cursor = 'move';
|
|
235
|
-
|
|
236
|
-
function onMove(e: MapMouseEvent | MapTouchEvent) {
|
|
237
|
-
e.preventDefault();
|
|
238
|
-
if (!draggingRotationHandle.current || !pdfContext.orientation || !pdfContext.geojsonRef)
|
|
239
|
-
return;
|
|
240
|
-
|
|
241
|
-
const tmpGeojsonProps = JSON.parse(JSON.stringify(geojsonProps));
|
|
242
|
-
const _bearing = turf.bearing(
|
|
243
|
-
[tmpGeojsonProps.center.lng, tmpGeojsonProps.center.lat],
|
|
244
|
-
[e.lngLat.lng, e.lngLat.lat]
|
|
245
|
-
);
|
|
246
|
-
tmpGeojsonProps.bearing = 144.7 + _bearing;
|
|
247
|
-
tmpGeojsonProps.geojson = createPreviewGeojson(tmpGeojsonProps, pdfContext.orientation);
|
|
248
|
-
pdfContext.geojsonRef.current = tmpGeojsonProps.geojson;
|
|
249
|
-
setGeojsonProps(tmpGeojsonProps);
|
|
250
|
-
}
|
|
251
|
-
function onUp() {
|
|
252
|
-
if (!draggingRotationHandle.current || !mapHook.map) return;
|
|
144
|
+
const _transform = `translate(${Math.floor(
|
|
145
|
+
centerInPixels.x - transformOrigin[0]
|
|
146
|
+
)}px,${Math.floor(centerInPixels.y - transformOrigin[1])}px) rotate(${
|
|
147
|
+
props.options.rotate - viewportBearing
|
|
148
|
+
}deg) scale(${scale},${scale})`;
|
|
253
149
|
|
|
254
|
-
|
|
255
|
-
draggingRotationHandle.current = false;
|
|
150
|
+
if (targetRef.current) targetRef.current.style.transform = _transform;
|
|
256
151
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
152
|
+
return _transform;
|
|
153
|
+
}, [
|
|
154
|
+
mapHook.map,
|
|
155
|
+
mapState.viewport,
|
|
156
|
+
props.options.scale,
|
|
157
|
+
props.options.rotate,
|
|
158
|
+
props.options.center,
|
|
159
|
+
transformOrigin,
|
|
160
|
+
]);
|
|
262
161
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
mapHook.map.map.once('mouseup', onUp);
|
|
267
|
-
mapHook.map.map.once('touchend', onUp);
|
|
268
|
-
},
|
|
269
|
-
});
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
moveableRef.current?.updateTarget();
|
|
164
|
+
}, [transform]);
|
|
270
165
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
useLayerEvent({
|
|
282
|
-
event: 'mouseleave',
|
|
283
|
-
layerId: 'pdfPreviewGeojson',
|
|
284
|
-
eventHandler: function () {
|
|
285
|
-
if (!mapHook.map) return;
|
|
286
|
-
|
|
287
|
-
mapHook.map.map._canvas.style.cursor = '';
|
|
288
|
-
mapHook.map.map.dragPan.enable();
|
|
289
|
-
activeFeature.current = undefined;
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
useLayerEvent({
|
|
293
|
-
event: 'mousedown',
|
|
294
|
-
addTouchEvents: true,
|
|
295
|
-
layerId: 'pdfPreviewGeojson',
|
|
296
|
-
eventHandler: function (e: MapMouseEvent | MapTouchEvent) {
|
|
297
|
-
e.preventDefault();
|
|
298
|
-
console.log('mousedown');
|
|
299
|
-
if (!mapHook.map) return;
|
|
300
|
-
|
|
301
|
-
draggingResizeHandle.current = false;
|
|
302
|
-
draggingRotationHandle.current = false;
|
|
303
|
-
dragging.current = true;
|
|
304
|
-
mapHook.map.map._canvas.style.cursor = 'move';
|
|
305
|
-
|
|
306
|
-
function onMove(e: MapMouseEvent | MapTouchEvent) {
|
|
307
|
-
e.preventDefault();
|
|
308
|
-
if (!dragging.current || !pdfContext.geojsonRef || !pdfContext.orientation) return;
|
|
309
|
-
|
|
310
|
-
const tmpGeojsonProps = JSON.parse(JSON.stringify(geojsonProps));
|
|
311
|
-
tmpGeojsonProps.center = e.lngLat;
|
|
312
|
-
tmpGeojsonProps.geojson = createPreviewGeojson(tmpGeojsonProps, pdfContext.orientation);
|
|
313
|
-
pdfContext.geojsonRef.current = tmpGeojsonProps.geojson;
|
|
314
|
-
setGeojsonProps(tmpGeojsonProps);
|
|
315
|
-
}
|
|
316
|
-
function onUp() {
|
|
317
|
-
if (!dragging.current || !mapHook.map) return;
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
// update props.options.scale if fixedScale was changed
|
|
168
|
+
if (
|
|
169
|
+
!mapHook.map ||
|
|
170
|
+
!props.options.center ||
|
|
171
|
+
!props.options.fixedScale ||
|
|
172
|
+
(typeof props.options.fixedScale !== 'undefined' &&
|
|
173
|
+
fixedScaleRef.current === props.options.fixedScale)
|
|
174
|
+
)
|
|
175
|
+
return;
|
|
318
176
|
|
|
319
|
-
|
|
320
|
-
|
|
177
|
+
fixedScaleRef.current = props.options.fixedScale;
|
|
178
|
+
const point = turf.point(props.options.center);
|
|
179
|
+
const distance = props.options.fixedScale * (props.options.width / 1000);
|
|
321
180
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
mapHook.map.map.off('touchmove', onMove);
|
|
326
|
-
}
|
|
181
|
+
const bearing = 90;
|
|
182
|
+
const options = { units: 'meters' as Units };
|
|
183
|
+
const destination = turf.destination(point, distance, bearing, options);
|
|
327
184
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
mapHook.map.map.once('touchend', onUp);
|
|
333
|
-
},
|
|
334
|
-
});
|
|
185
|
+
const centerInPixels = mapHook.map.map.project(point.geometry.coordinates as LngLatLike);
|
|
186
|
+
const destinationInPixels = mapHook.map.map.project(
|
|
187
|
+
destination.geometry.coordinates as LngLatLike
|
|
188
|
+
);
|
|
335
189
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
//});
|
|
190
|
+
const scaleFactor =
|
|
191
|
+
(Math.round(destinationInPixels.x - centerInPixels.x) / props.options.width) *
|
|
192
|
+
(1 / getMapZoomScaleModifier([centerInPixels.x, centerInPixels.y], mapHook.map.map));
|
|
193
|
+
props.setOptions((val: PdfPreviewOptions) => ({ ...val, scale: [scaleFactor, scaleFactor] }));
|
|
194
|
+
}, [mapHook.map, props.options.width, props.options.center, props.options.fixedScale]);
|
|
342
195
|
|
|
343
|
-
|
|
196
|
+
// update props.geoJsonRef
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
if (targetRef.current && mapHook.map) {
|
|
199
|
+
// apply orientation
|
|
200
|
+
let _width = props.options.width;
|
|
201
|
+
let _height = props.options.height;
|
|
202
|
+
if (props.options.orientation === 'portrait') {
|
|
203
|
+
targetRef.current.style.width = props.options.width + 'px';
|
|
204
|
+
targetRef.current.style.height = props.options.height + 'px';
|
|
205
|
+
} else {
|
|
206
|
+
targetRef.current.style.width = props.options.height + 'px';
|
|
207
|
+
targetRef.current.style.height = props.options.width + 'px';
|
|
208
|
+
_width = props.options.height;
|
|
209
|
+
_height = props.options.width;
|
|
210
|
+
}
|
|
211
|
+
moveableRef.current?.updateTarget();
|
|
212
|
+
|
|
213
|
+
const topLeft = mapHook.map.map.unproject(
|
|
214
|
+
calcElemTransformedPoint(targetRef.current, [0, 0], transformOrigin)
|
|
215
|
+
);
|
|
216
|
+
const topRight = mapHook.map.map.unproject(
|
|
217
|
+
calcElemTransformedPoint(targetRef.current, [_width, 0], transformOrigin)
|
|
218
|
+
);
|
|
219
|
+
const bottomLeft = mapHook.map.map.unproject(
|
|
220
|
+
calcElemTransformedPoint(targetRef.current, [0, _height], transformOrigin)
|
|
221
|
+
);
|
|
222
|
+
const bottomRight = mapHook.map.map.unproject(
|
|
223
|
+
calcElemTransformedPoint(targetRef.current, [_width, _height], transformOrigin)
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const _geoJson = {
|
|
227
|
+
type: 'Feature',
|
|
228
|
+
bbox: [topLeft.lng, topLeft.lat, bottomRight.lng, bottomRight.lat],
|
|
229
|
+
geometry: {
|
|
230
|
+
type: 'Polygon',
|
|
231
|
+
coordinates: [
|
|
232
|
+
[
|
|
233
|
+
[topLeft.lng, topLeft.lat],
|
|
234
|
+
[topRight.lng, topRight.lat],
|
|
235
|
+
[bottomRight.lng, bottomRight.lat],
|
|
236
|
+
[bottomLeft.lng, bottomLeft.lat],
|
|
237
|
+
[topLeft.lng, topLeft.lat],
|
|
238
|
+
],
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
properties: { bearing: getTargetRotationAngle(targetRef.current) },
|
|
242
|
+
} as Feature;
|
|
243
|
+
props.geojsonRef.current = _geoJson;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return undefined;
|
|
247
|
+
}, [
|
|
248
|
+
mapHook,
|
|
249
|
+
transform,
|
|
250
|
+
props.options.orientation,
|
|
251
|
+
props.geojsonRef,
|
|
252
|
+
mapState,
|
|
253
|
+
targetRef.current,
|
|
254
|
+
transformOrigin,
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
return mapContainerRef.current ? ReactDOM.createPortal(
|
|
344
258
|
<>
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
259
|
+
<div
|
|
260
|
+
className="target"
|
|
261
|
+
ref={targetRef}
|
|
262
|
+
style={{ transform: transform, transformOrigin: 'center center' }}
|
|
263
|
+
></div>
|
|
264
|
+
<Moveable
|
|
265
|
+
// eslint-disable-next-line
|
|
266
|
+
// @ts-ignore:
|
|
267
|
+
ref={moveableRef}
|
|
268
|
+
target={targetRef}
|
|
269
|
+
container={null}
|
|
270
|
+
origin={true}
|
|
271
|
+
keepRatio={true}
|
|
272
|
+
/* draggable */
|
|
273
|
+
draggable={true}
|
|
274
|
+
onDrag={(e) => {
|
|
275
|
+
if (mapHook.map) {
|
|
276
|
+
|
|
277
|
+
let _transformParts = e.transform.split('translate(');
|
|
278
|
+
_transformParts = _transformParts[1].split('px)')[0].split('px, ');
|
|
279
|
+
const _center = mapHook.map?.map.unproject([
|
|
280
|
+
parseInt(_transformParts[0]) + transformOrigin[0],
|
|
281
|
+
parseInt(_transformParts[1]) + transformOrigin[1],
|
|
282
|
+
]);
|
|
283
|
+
props.setOptions((val: PdfPreviewOptions) => ({
|
|
284
|
+
...val,
|
|
285
|
+
center: [_center.lng, _center.lat],
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
}}
|
|
289
|
+
/* scalable */
|
|
290
|
+
scalable={props.options.fixedScale ? false : true}
|
|
291
|
+
onScale={(e) => {
|
|
292
|
+
if (mapHook.map) {
|
|
293
|
+
let _transformParts = e.drag.transform.split('scale(');
|
|
294
|
+
_transformParts = _transformParts[1].split(')')[0].split(', ');
|
|
295
|
+
|
|
296
|
+
const centerInPixels = mapHook.map.map.project(props.options.center as LngLatLike);
|
|
297
|
+
|
|
298
|
+
const x = centerInPixels.x;
|
|
299
|
+
const y = centerInPixels.y;
|
|
300
|
+
|
|
301
|
+
const scale =
|
|
302
|
+
parseFloat(_transformParts[0]) *
|
|
303
|
+
(1 / getMapZoomScaleModifier([x, y], mapHook.map.map));
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
props.setOptions((val: PdfPreviewOptions) => ({ ...val, scale: [scale, scale] }));
|
|
307
|
+
}
|
|
308
|
+
}}
|
|
309
|
+
/* rotatable */
|
|
310
|
+
rotatable={true}
|
|
311
|
+
onRotate={(e) => {
|
|
312
|
+
if (mapHook.map && mapState.viewport) {
|
|
313
|
+
const _transformParts = e.drag.transform.split('rotate(');
|
|
314
|
+
const _transformPartString = _transformParts[1].split('deg)')[0];
|
|
315
|
+
const viewportBearing = mapState?.viewport?.bearing ? mapState.viewport.bearing : 0;
|
|
316
|
+
|
|
317
|
+
props.setOptions((val: PdfPreviewOptions) => ({
|
|
318
|
+
...val,
|
|
319
|
+
rotate: parseFloat(_transformPartString) + viewportBearing,
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
}}
|
|
323
|
+
/>
|
|
324
|
+
</>,
|
|
325
|
+
mapContainerRef.current
|
|
326
|
+
):<></>;
|
|
399
327
|
}
|