@vcmap/core 5.0.0-rc.23 → 5.0.0-rc.25

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.
Files changed (65) hide show
  1. package/index.d.ts +824 -200
  2. package/index.js +24 -10
  3. package/package.json +2 -2
  4. package/src/category/category.js +1 -1
  5. package/src/featureProvider/abstractFeatureProvider.js +1 -18
  6. package/src/interaction/eventHandler.js +14 -0
  7. package/src/layer/cesium/cesiumTilesetCesiumImpl.js +4 -19
  8. package/src/layer/cesium/clusterContext.js +18 -0
  9. package/src/layer/cesium/vectorCesiumImpl.js +17 -2
  10. package/src/layer/cesium/vectorContext.js +187 -11
  11. package/src/layer/cesium/vectorRasterTileCesiumImpl.js +0 -1
  12. package/src/layer/cesiumTilesetLayer.js +1 -63
  13. package/src/layer/czmlLayer.js +1 -1
  14. package/src/layer/dataSourceLayer.js +1 -53
  15. package/src/layer/featureLayer.js +42 -38
  16. package/src/layer/featureStoreLayer.js +0 -15
  17. package/src/layer/layer.js +6 -11
  18. package/src/layer/layerSymbols.js +2 -1
  19. package/src/layer/oblique/vectorObliqueImpl.js +6 -0
  20. package/src/layer/openStreetMapLayer.js +6 -0
  21. package/src/layer/openlayers/layerOpenlayersImpl.js +69 -4
  22. package/src/layer/openlayers/rasterLayerOpenlayersImpl.js +0 -80
  23. package/src/layer/rasterLayer.js +1 -1
  24. package/src/layer/vectorHelpers.js +0 -85
  25. package/src/layer/vectorLayer.js +1 -9
  26. package/src/layer/vectorProperties.js +150 -8
  27. package/src/layer/vectorTileLayer.js +0 -9
  28. package/src/map/baseOLMap.js +17 -0
  29. package/src/map/cesiumMap.js +46 -8
  30. package/src/map/vcsMap.js +23 -5
  31. package/src/style/arcStyle.js +316 -0
  32. package/src/style/arrowStyle.js +269 -0
  33. package/src/util/editor/createFeatureSession.js +3 -1
  34. package/src/util/editor/editFeaturesSession.js +315 -0
  35. package/src/util/editor/editGeometrySession.js +5 -1
  36. package/src/util/editor/editorHelpers.js +118 -14
  37. package/src/util/editor/editorSessionHelpers.js +12 -0
  38. package/src/util/editor/editorSymbols.js +6 -0
  39. package/src/util/editor/interactions/editFeaturesMouseOverInteraction.js +120 -0
  40. package/src/util/editor/interactions/editGeometryMouseOverInteraction.js +1 -3
  41. package/src/util/editor/interactions/ensureHandlerSelectionInteraction.js +48 -0
  42. package/src/util/editor/interactions/mapInteractionController.js +5 -2
  43. package/src/util/editor/interactions/selectMultiFeatureInteraction.js +146 -0
  44. package/src/util/editor/interactions/translateVertexInteraction.js +2 -2
  45. package/src/util/editor/transformation/create2DHandlers.js +294 -0
  46. package/src/util/editor/transformation/create3DHandlers.js +575 -0
  47. package/src/util/editor/transformation/extrudeInteraction.js +91 -0
  48. package/src/util/editor/transformation/rotateInteraction.js +188 -0
  49. package/src/util/editor/transformation/scaleInteraction.js +185 -0
  50. package/src/util/editor/transformation/transformationHandler.js +168 -0
  51. package/src/util/editor/transformation/transformationTypes.js +83 -0
  52. package/src/util/editor/transformation/translateInteraction.js +209 -0
  53. package/src/util/featureconverter/arcToCesium.js +87 -0
  54. package/src/util/featureconverter/convert.js +7 -1
  55. package/src/util/featureconverter/extent3D.js +64 -1
  56. package/src/util/featureconverter/lineStringToCesium.js +103 -2
  57. package/src/util/featureconverter/pointHelpers.js +341 -0
  58. package/src/util/featureconverter/pointToCesium.js +27 -76
  59. package/src/util/geometryHelpers.js +11 -8
  60. package/src/util/mapCollection.js +30 -24
  61. package/src/util/math.js +99 -2
  62. package/tests/unit/helpers/cesiumHelpers.js +14 -4
  63. package/tests/unit/helpers/helpers.js +13 -0
  64. package/src/featureProvider/featureProviderHelpers.js +0 -50
  65. package/src/util/splitScreen.js +0 -233
@@ -108,10 +108,8 @@ class EditGeometryMouseOverInteraction extends AbstractInteraction {
108
108
  if (this._lastFeature[vertexSymbol]) {
109
109
  if (modifier === ModificationKeyType.SHIFT) {
110
110
  this.cursorStyle.cursor = cursorMap.removeVertex;
111
- } else if (modifier === ModificationKeyType.ALT) {
112
- this.cursorStyle.cursor = cursorMap.translateVertex;
113
111
  } else {
114
- this.cursorStyle.cursor = cursorMap.auto;
112
+ this.cursorStyle.cursor = cursorMap.translateVertex;
115
113
  }
116
114
  } else {
117
115
  this.cursorStyle.cursor = cursorMap.select;
@@ -0,0 +1,48 @@
1
+ import AbstractInteraction from '../../../interaction/abstractInteraction.js';
2
+ import { EventType } from '../../../interaction/interactionType.js';
3
+ import { handlerSymbol } from '../../../../index.js';
4
+ import CesiumMap from '../../../map/cesiumMap.js';
5
+
6
+ /**
7
+ * This interaction ensure a potential handler is dragged in 3D when it is obscured by a transparent feature.
8
+ * It uses drillPick on MOVE if: the map is 3D, there is a feature at said position, there is a feature selected in
9
+ * the feature selection & the feature at the position is _not_ a handler
10
+ * @class
11
+ */
12
+ class EnsureHandlerSelectionInteraction extends AbstractInteraction {
13
+ /**
14
+ * @param {import("@vcmap/core").SelectMultiFeatureInteraction} selectMultiFeatureInteraction
15
+ */
16
+ constructor(selectMultiFeatureInteraction) {
17
+ super(EventType.DRAGSTART | EventType.MOVE);
18
+ /**
19
+ * @type {import("@vcmap/core").SelectMultiFeatureInteraction}
20
+ * @private
21
+ */
22
+ this._featureSelection = selectMultiFeatureInteraction;
23
+ }
24
+
25
+ /**
26
+ * @param {InteractionEvent} event
27
+ * @returns {Promise<InteractionEvent>}
28
+ */
29
+ async pipe(event) {
30
+ if (
31
+ event.feature &&
32
+ this._featureSelection.selectedFeatures.length > 0 &&
33
+ !event.feature[handlerSymbol] &&
34
+ event.map instanceof CesiumMap
35
+ ) {
36
+ const handler = event.map.getScene().drillPick(event.windowPosition, undefined, 10, 10)
37
+ .find((p) => {
38
+ return p?.primitive?.olFeature?.[handlerSymbol];
39
+ });
40
+ if (handler) {
41
+ event.feature = handler.primitive.olFeature;
42
+ }
43
+ }
44
+ return event;
45
+ }
46
+ }
47
+
48
+ export default EnsureHandlerSelectionInteraction;
@@ -1,6 +1,6 @@
1
1
  import DragPan from 'ol/interaction/DragPan.js';
2
2
  import { EventType, ModificationKeyType } from '../../../interaction/interactionType.js';
3
- import { vertexSymbol } from '../editorSymbols.js';
3
+ import { handlerSymbol, vertexSymbol } from '../editorSymbols.js';
4
4
  import AbstractInteraction from '../../../interaction/abstractInteraction.js';
5
5
 
6
6
  /**
@@ -75,7 +75,10 @@ class MapInteractionController extends AbstractInteraction {
75
75
  */
76
76
  async pipe(event) {
77
77
  this.reset();
78
- if (event.feature && event.feature[vertexSymbol]) {
78
+ if (
79
+ event.feature &&
80
+ (event.feature[vertexSymbol] || event.feature[handlerSymbol])
81
+ ) {
79
82
  if (event.map.className === 'CesiumMap') {
80
83
  this._clear = suspendCesiumMap(/** @type {import("@vcmap/core").CesiumMap} */ (event.map));
81
84
  } else {
@@ -0,0 +1,146 @@
1
+ import AbstractInteraction from '../../../interaction/abstractInteraction.js';
2
+ import { EventType, ModificationKeyType } from '../../../interaction/interactionType.js';
3
+ import VcsEvent from '../../../vcsEvent.js';
4
+ import { vcsLayerName } from '../../../layer/layerSymbols.js';
5
+ import { isTiledFeature } from '../../../layer/featureStoreLayer.js';
6
+
7
+ /**
8
+ * Interaction to create a selection set from the given layer.
9
+ * Will use CTRL modifier key to add more features to the set.
10
+ * Clears the set if not clicking a feature
11
+ * Creates a new set when clicking a feature
12
+ * FeatureStore features will be converted to their dynamic state on selection.
13
+ * @class
14
+ * @extends {AbstractInteraction}
15
+ */
16
+ class SelectMultiFeatureInteraction extends AbstractInteraction {
17
+ /**
18
+ * @param {import("@vcmap/core").VectorLayer} layer
19
+ */
20
+ constructor(layer) {
21
+ super(EventType.CLICK, ModificationKeyType.NONE | ModificationKeyType.CTRL);
22
+ /**
23
+ * @type {import("@vcmap/core").VectorLayer|import("@vcmap/core").FeatureStoreLayer}
24
+ * @private
25
+ */
26
+ this._layer = layer;
27
+ /**
28
+ * @type {Map<string|number, import("ol").Feature>}
29
+ * @private
30
+ */
31
+ this._selectedFeatures = new Map();
32
+ /**
33
+ * @type {VcsEvent<Array<import("ol").Feature>>}
34
+ * @private
35
+ */
36
+ this._featuresChanged = new VcsEvent();
37
+ this.setActive();
38
+ }
39
+
40
+ /**
41
+ * Event raised when the feature selection changes. Will be called with an array of features or an empty array, when no feature is selected
42
+ * @type {VcsEvent<Array<import("ol").Feature>>}
43
+ * @readonly
44
+ */
45
+ get featuresChanged() { return this._featuresChanged; }
46
+
47
+ /**
48
+ * @returns {Array<import("ol").Feature>}
49
+ */
50
+ get selectedFeatures() {
51
+ return [...this._selectedFeatures.values()];
52
+ }
53
+
54
+ /**
55
+ * @param {string} featureId
56
+ * @returns {boolean}
57
+ */
58
+ hasFeatureId(featureId) {
59
+ return this._selectedFeatures.has(featureId);
60
+ }
61
+
62
+ /**
63
+ * @inheritDoc
64
+ * @param {InteractionEvent} event
65
+ * @returns {Promise<InteractionEvent>}
66
+ */
67
+ async pipe(event) {
68
+ if (
69
+ event.feature &&
70
+ event.feature[vcsLayerName] === this._layer.name
71
+ ) {
72
+ if (event.key & ModificationKeyType.CTRL) {
73
+ event.stopPropagation = true;
74
+ await this._modifySelectionSet(event.feature);
75
+ } else if (!this._selectedFeatures.has(event.feature.getId())) {
76
+ event.stopPropagation = true;
77
+ await this.setSelectionSet([event.feature]);
78
+ }
79
+ } else if (!(event.key & ModificationKeyType.CTRL)) {
80
+ this.clear();
81
+ }
82
+ return event;
83
+ }
84
+
85
+ /**
86
+ * @param {Array<import("ol").Feature|import("@vcmap/cesium").Cesium3DTileFeature|import("@vcmap/cesium").Cesium3DTilePointFeature|import("@vcmap/cesium").Entity>} features
87
+ * @returns {Promise<void>}
88
+ */
89
+ async setSelectionSet(features) {
90
+ this._selectedFeatures.clear();
91
+ const olFeatures = await Promise.all(features.map((f) => {
92
+ if (f[isTiledFeature]) {
93
+ return /** @type {import("@vcmap/core").FeatureStoreLayer} */ (this._layer)
94
+ .switchStaticFeatureToDynamic(f.getId());
95
+ }
96
+ return f;
97
+ }));
98
+ olFeatures.forEach(/** @param {import("ol").Feature} f */ (f) => {
99
+ this._selectedFeatures.set(f.getId(), f);
100
+ });
101
+
102
+ this._featuresChanged.raiseEvent(this.selectedFeatures);
103
+ }
104
+
105
+ /**
106
+ * @param {import("ol").Feature|import("@vcmap/cesium").Cesium3DTileFeature|import("@vcmap/cesium").Cesium3DTilePointFeature|import("@vcmap/cesium").Entity} feature
107
+ * @returns {Promise<void>}
108
+ * @private
109
+ */
110
+ async _modifySelectionSet(feature) {
111
+ const id = feature.getId();
112
+ if (this._selectedFeatures.has(id)) {
113
+ this._selectedFeatures.delete(id);
114
+ } else {
115
+ let olFeature = feature;
116
+ if (feature[isTiledFeature]) {
117
+ olFeature = await /** @type {import("@vcmap/core").FeatureStoreLayer} */ (this._layer)
118
+ .switchStaticFeatureToDynamic(id);
119
+ }
120
+ this._selectedFeatures.set(id, /** @type {import("ol").Feature} */ (olFeature));
121
+ }
122
+
123
+ this._featuresChanged.raiseEvent(this.selectedFeatures);
124
+ }
125
+
126
+ /**
127
+ * Clears the interaction, removing all features and calling the featureChange event with an empty array
128
+ */
129
+ clear() {
130
+ if (this._selectedFeatures.size > 0) {
131
+ this._selectedFeatures.clear();
132
+ this._featuresChanged.raiseEvent([]);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @inheritDoc
138
+ */
139
+ destroy() {
140
+ this._selectedFeatures.clear();
141
+ this._featuresChanged.destroy();
142
+ super.destroy();
143
+ }
144
+ }
145
+
146
+ export default SelectMultiFeatureInteraction;
@@ -1,5 +1,5 @@
1
1
  import AbstractInteraction from '../../../interaction/abstractInteraction.js';
2
- import { EventType, ModificationKeyType } from '../../../interaction/interactionType.js';
2
+ import { EventType } from '../../../interaction/interactionType.js';
3
3
  import { vertexSymbol } from '../editorSymbols.js';
4
4
  import { emptyStyle } from '../../../style/styleHelpers.js';
5
5
  import VcsEvent from '../../../vcsEvent.js';
@@ -12,7 +12,7 @@ import VcsEvent from '../../../vcsEvent.js';
12
12
  */
13
13
  class TranslateVertexInteraction extends AbstractInteraction {
14
14
  constructor() {
15
- super(EventType.DRAGEVENTS, ModificationKeyType.ALT);
15
+ super(EventType.DRAGEVENTS);
16
16
  /**
17
17
  * @type {import("@vcmap/core").VcsEvent<Vertex>}
18
18
  */
@@ -0,0 +1,294 @@
1
+ import { Feature } from 'ol';
2
+ import { Circle, LineString, Point, Polygon } from 'ol/geom.js';
3
+ import { Fill, Icon, Stroke, Style } from 'ol/style.js';
4
+ import { Color } from '@vcmap/cesium';
5
+ import { unByKey } from 'ol/Observable.js';
6
+ import { handlerSymbol } from '../editorSymbols.js';
7
+ import { AXIS_AND_PLANES, greyedOutColor, is1DAxis, is2DAxis, TransformationMode } from './transformationTypes.js';
8
+ import { mercatorProjection } from '../../projection.js';
9
+ import Vector from '../../../layer/vectorLayer.js';
10
+
11
+ /**
12
+ * @param {import("ol/coordinate").Coordinate} center
13
+ * @param {AXIS_AND_PLANES} axis
14
+ * @param {import("ol/extent").Extent} extent
15
+ * @returns {Array<import("ol/coordinate").Coordinate>}
16
+ */
17
+ function createAxisPositions(center, axis, extent) {
18
+ if (axis === AXIS_AND_PLANES.X) {
19
+ return [
20
+ [extent[0], center[1], center[2]],
21
+ [center[0], center[1], center[2]],
22
+ [extent[2], center[1], center[2]],
23
+ ];
24
+ }
25
+
26
+ return [
27
+ [center[0], extent[1], center[2]],
28
+ [center[0], center[1], center[2]],
29
+ [center[0], extent[3], center[2]],
30
+ ];
31
+ }
32
+
33
+ /**
34
+ * Creates a function to add axis to the scratch layer. To cleanup features created by this function, you can call
35
+ * it with AXIS_AND_PLANES.NONE.
36
+ * @param {import("@vcmap/core").VectorLayer} scratchLayer
37
+ * @param {import("ol/extent").Extent} [projectionExtent]
38
+ * @returns {function(AXIS_AND_PLANES, import("ol/coordinate").Coordinate):void}
39
+ */
40
+ function createShowAxisFeatures(scratchLayer, projectionExtent) {
41
+ let featureIds;
42
+ const extent = projectionExtent ?? mercatorProjection.proj.getExtent();
43
+
44
+ return (axis, center) => {
45
+ if (featureIds) {
46
+ scratchLayer.removeFeaturesById(featureIds);
47
+ featureIds = null;
48
+ }
49
+ if (axis !== AXIS_AND_PLANES.NONE) {
50
+ const features = [];
51
+ if (axis === AXIS_AND_PLANES.X || axis === AXIS_AND_PLANES.XY) {
52
+ const feature = new Feature({
53
+ geometry: new LineString(createAxisPositions(center, AXIS_AND_PLANES.X, extent)),
54
+ });
55
+ feature.setStyle(new Style({
56
+ stroke: new Stroke({ color: Color.RED.withAlpha(0.5).toCssColorString(), width: 1 }),
57
+ }));
58
+ features.push(feature);
59
+ }
60
+ if (axis === AXIS_AND_PLANES.Y || axis === AXIS_AND_PLANES.XY) {
61
+ const feature = new Feature({
62
+ geometry: new LineString(createAxisPositions(center, AXIS_AND_PLANES.Y, extent)),
63
+ });
64
+ feature.setStyle(new Style({
65
+ stroke: new Stroke({ color: Color.GREEN.withAlpha(0.5).toCssColorString(), width: 1 }),
66
+ }));
67
+ features.push(feature);
68
+ }
69
+ features.forEach((f) => {
70
+ const geometry = f.getGeometry();
71
+ geometry[Vector.alreadyTransformedToImage] = true;
72
+ geometry[Vector.doNotTransform] = true;
73
+ });
74
+ featureIds = scratchLayer.addFeatures(features);
75
+ }
76
+ };
77
+ }
78
+
79
+ /**
80
+ * @param {AXIS_AND_PLANES} axis
81
+ * @param {TransformationMode} mode
82
+ * @param {string=} [colorOverride]
83
+ * @returns {Array<import("ol").Feature>}
84
+ */
85
+ function createLineAxisFeatures(axis, mode, colorOverride) {
86
+ let color;
87
+ let coordinates;
88
+ let rotation = 0;
89
+
90
+ if (axis === AXIS_AND_PLANES.X) {
91
+ color = Color.RED.toCssColorString();
92
+ coordinates = [[0, 0, 0], [1, 0, 0]];
93
+ rotation = Math.PI / 2;
94
+ } else {
95
+ color = Color.GREEN.toCssColorString();
96
+ coordinates = [[0, 0, 0], [0, 1, 0]];
97
+ }
98
+ color = colorOverride ?? color;
99
+ let src;
100
+ if (mode === TransformationMode.TRANSLATE) {
101
+ src = '<svg height="13" width="13" xmlns="http://www.w3.org/2000/svg"><polygon points="0,13 13,13 6,0" style="fill:white;" /></svg>'; // an arrow svg
102
+ } else {
103
+ src = '<svg height="13" width="13" xmlns="http://www.w3.org/2000/svg"><polygon points="0,0 13,0 13,13 0,13" style="fill:white" /></svg>'; // a cube svg
104
+ }
105
+ src = `data:image/svg+xml,${encodeURIComponent(src)}`;
106
+
107
+ const features = [
108
+ new Feature({
109
+ geometry: new Point(coordinates[1].slice()),
110
+ axis,
111
+ }),
112
+ new Feature({
113
+ geometry: new LineString(coordinates),
114
+ axis,
115
+ }),
116
+ ];
117
+ features[0].setStyle(new Style({
118
+ image: new Icon({
119
+ src,
120
+ anchor: [0.5, 1],
121
+ color,
122
+ rotation,
123
+ }),
124
+ }));
125
+ features[1].setStyle(new Style({ stroke: new Stroke({ color, width: 4 }) }));
126
+
127
+ return features;
128
+ }
129
+
130
+ /**
131
+ * @param {string=} [colorOverride]
132
+ * @returns {import("ol").Feature<Polygon>}
133
+ */
134
+ function createPlaneFeature(colorOverride) {
135
+ const feature = new Feature({
136
+ geometry: new Polygon([[
137
+ [0.2, 0.2, 0],
138
+ [0.2, 0.4, 0],
139
+ [0.4, 0.4, 0],
140
+ [0.4, 0.2, 0],
141
+ [0.2, 0.2, 0],
142
+ ]]),
143
+ axis: AXIS_AND_PLANES.XY,
144
+ });
145
+ const color = colorOverride ?? Color.BLUE.toCssColorString();
146
+ feature.setStyle(new Style({ fill: new Fill({ color }) }));
147
+ return feature;
148
+ }
149
+
150
+ /**
151
+ * Creates a function to add a shadow (greyed out clone of a handler) to the scratch layer. To cleanup features created by this function, you can call
152
+ * it with AXIS_AND_PLANES.NONE.
153
+ * @param {import("@vcmap/core").VectorLayer} scratchLayer
154
+ * @returns {function(AXIS_AND_PLANES, TransformationMode, import("ol/coordinate").Coordinate, number):void}
155
+ */
156
+ function createShowShadowFeatures(scratchLayer) {
157
+ let featureIds;
158
+ const color = greyedOutColor.toCssColorString();
159
+
160
+ return (axis, mode, center, scale) => {
161
+ if (featureIds) {
162
+ scratchLayer.removeFeaturesById(featureIds);
163
+ featureIds = null;
164
+ }
165
+ if (axis !== AXIS_AND_PLANES.NONE) {
166
+ let features = [];
167
+ if (is1DAxis(axis)) {
168
+ features = createLineAxisFeatures(axis, mode, color);
169
+ } else if (is2DAxis(axis)) {
170
+ features = [createPlaneFeature(color)];
171
+ }
172
+ features.forEach((f) => {
173
+ f.getGeometry().applyTransform((input, output) => {
174
+ const inputLength = input.length;
175
+ for (let i = 0; i < inputLength; i += 3) {
176
+ output[i] = (input[i] * scale) + center[0];
177
+ output[i + 1] = (input[i + 1] * scale) + center[1];
178
+ output[i + 2] = 0;
179
+ }
180
+ return output;
181
+ });
182
+ });
183
+ featureIds = scratchLayer.addFeatures(features);
184
+ }
185
+ };
186
+ }
187
+
188
+ /**
189
+ * The function will create 2D handlers for the {@see OpenlayerMap} and the {@see ObliqueMap} depending on the provided mode.
190
+ * In most scenarios, handlers must not be created using this function, but using the startEditFeaturesSession or for lower
191
+ * level access the createTransformationHandler instead.
192
+ * @param {import("@vcmap/core").BaseOLMap} map
193
+ * @param {import("@vcmap/core").VectorLayer} scratchLayer
194
+ * @param {TransformationMode} mode
195
+ * @returns {Handlers}
196
+ */
197
+ export default function create2DHandlers(map, scratchLayer, mode) {
198
+ let center = [0, 0, 0];
199
+ let scale = 1;
200
+ let features = [];
201
+ if (mode === TransformationMode.TRANSLATE || mode === TransformationMode.SCALE) {
202
+ features = [
203
+ ...createLineAxisFeatures(AXIS_AND_PLANES.X, mode),
204
+ ...createLineAxisFeatures(AXIS_AND_PLANES.Y, mode),
205
+ createPlaneFeature(),
206
+ ];
207
+ } else if (mode === TransformationMode.ROTATE) {
208
+ features = [
209
+ new Feature({
210
+ geometry: new Circle([0, 0, 0], 0.5),
211
+ axis: AXIS_AND_PLANES.Z,
212
+ }),
213
+ ];
214
+ features[0].setStyle(new Style({ stroke: new Stroke({ color: Color.BLUE.toCssColorString(), width: 2 }) }));
215
+ }
216
+
217
+ features.forEach((f) => {
218
+ const geometry = f.getGeometry();
219
+ geometry[Vector.alreadyTransformedToImage] = true;
220
+ geometry[Vector.doNotTransform] = true;
221
+ f[handlerSymbol] = f.get('axis');
222
+ });
223
+
224
+ const postRenderListenerKey = map.olMap.on('postrender', () => {
225
+ if (!(center[0] === 0 && center[1] === 0 && center[2] === 0)) {
226
+ const res = map.getCurrentResolution(center) * 60;
227
+ const factor = res / scale;
228
+ if (factor !== 1) {
229
+ features.forEach((f) => {
230
+ f.getGeometry().applyTransform((input, output) => {
231
+ const inputLength = input.length;
232
+ for (let i = 0; i < inputLength; i += 3) {
233
+ output[i] = ((input[i] - center[0]) * factor) + center[0];
234
+ output[i + 1] = ((input[i + 1] - center[1]) * factor) + center[1];
235
+ output[i + 2] = 0;
236
+ }
237
+ return output;
238
+ });
239
+ });
240
+ }
241
+
242
+ scale = res;
243
+ }
244
+ });
245
+
246
+ let showAxis = AXIS_AND_PLANES.NONE;
247
+ const showAxisFeatures = createShowAxisFeatures(scratchLayer);
248
+ const showShadowFeatures = createShowShadowFeatures(scratchLayer);
249
+
250
+ let showing = false;
251
+
252
+ return {
253
+ get show() { return showing; },
254
+ set show(show) {
255
+ if (show !== showing) {
256
+ showing = show;
257
+ if (!show) {
258
+ scratchLayer.removeFeaturesById(features.map(f => f.getId()));
259
+ } else {
260
+ scratchLayer.addFeatures(features);
261
+ }
262
+ }
263
+ },
264
+ get showAxis() { return showAxis; },
265
+ set showAxis(axis) {
266
+ showAxis = axis;
267
+ showAxisFeatures(axis, center);
268
+ showShadowFeatures(axis, mode, center, scale);
269
+ },
270
+ greyOutZ: false,
271
+ setCenter(newCenter) {
272
+ const dx = newCenter[0] - center[0];
273
+ const dy = newCenter[1] - center[1];
274
+ features.forEach((f) => {
275
+ f.getGeometry().applyTransform((input, output) => {
276
+ const inputLength = input.length;
277
+ for (let i = 0; i < inputLength; i += 3) {
278
+ output[i] = input[i] + dx;
279
+ output[i + 1] = input[i + 1] + dy;
280
+ output[i + 2] = input[i + 2];
281
+ }
282
+ return output;
283
+ });
284
+ });
285
+ center = newCenter.slice();
286
+ },
287
+ destroy() {
288
+ unByKey(postRenderListenerKey);
289
+ showAxisFeatures(AXIS_AND_PLANES.NONE, center);
290
+ showShadowFeatures(AXIS_AND_PLANES.NONE, mode, center, scale);
291
+ scratchLayer.removeFeaturesById(features.map(f => f.getId()).filter(id => id));
292
+ },
293
+ };
294
+ }