@artstesh/maps 4.1.1 → 4.1.3

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 (57) hide show
  1. package/dist/esm2020/map/map-plate/features/markers/markers.component.mjs +3 -3
  2. package/dist/esm2020/map/map-plate/features/polygons/polygons.component.mjs +2 -2
  3. package/dist/esm2020/map/map-plate/layers/feature-layer/feature-layer.settings.mjs +44 -1
  4. package/dist/esm2020/map/map-plate/map-plate.component.mjs +4 -1
  5. package/dist/esm2020/map/messages/commands/add-control.command.mjs +12 -0
  6. package/dist/esm2020/map/messages/commands/remove-control.command.mjs +12 -0
  7. package/dist/esm2020/map/messages/commands/set-map-center.command.mjs +23 -0
  8. package/dist/esm2020/map/messages/index.mjs +4 -1
  9. package/dist/esm2020/map/models/index.mjs +2 -1
  10. package/dist/esm2020/map/models/map-control.mjs +15 -0
  11. package/dist/esm2020/map/services/controls/controls.service.mjs +37 -0
  12. package/dist/esm2020/map/services/map-management.service.mjs +2 -2
  13. package/dist/esm2020/map/services/map-state.service.mjs +19 -4
  14. package/dist/esm2020/map/services/message-registrator.service.mjs +12 -5
  15. package/dist/esm2020/src/map/map-plate/features/markers/markers.component.mjs +3 -3
  16. package/dist/esm2020/src/map/map-plate/features/polygons/polygons.component.mjs +2 -2
  17. package/dist/esm2020/src/map/map-plate/layers/feature-layer/feature-layer.settings.mjs +44 -1
  18. package/dist/esm2020/src/map/map-plate/map-plate.component.mjs +4 -1
  19. package/dist/esm2020/src/map/messages/commands/add-control.command.mjs +12 -0
  20. package/dist/esm2020/src/map/messages/commands/remove-control.command.mjs +12 -0
  21. package/dist/esm2020/src/map/messages/commands/set-map-center.command.mjs +23 -0
  22. package/dist/esm2020/src/map/messages/index.mjs +4 -1
  23. package/dist/esm2020/src/map/models/index.mjs +2 -1
  24. package/dist/esm2020/src/map/models/map-control.mjs +15 -0
  25. package/dist/esm2020/src/map/services/controls/controls.service.mjs +37 -0
  26. package/dist/esm2020/src/map/services/map-management.service.mjs +2 -2
  27. package/dist/esm2020/src/map/services/map-state.service.mjs +19 -4
  28. package/dist/esm2020/src/map/services/message-registrator.service.mjs +12 -5
  29. package/dist/fesm2015/maps-components-src-map.mjs +165 -12
  30. package/dist/fesm2015/maps-components-src-map.mjs.map +1 -1
  31. package/dist/fesm2015/maps-components.mjs +165 -12
  32. package/dist/fesm2015/maps-components.mjs.map +1 -1
  33. package/dist/fesm2020/maps-components-src-map.mjs +163 -11
  34. package/dist/fesm2020/maps-components-src-map.mjs.map +1 -1
  35. package/dist/fesm2020/maps-components.mjs +163 -11
  36. package/dist/fesm2020/maps-components.mjs.map +1 -1
  37. package/dist/map/map-plate/layers/feature-layer/feature-layer.settings.d.ts +46 -0
  38. package/dist/map/messages/commands/add-control.command.d.ts +8 -0
  39. package/dist/map/messages/commands/remove-control.command.d.ts +8 -0
  40. package/dist/map/messages/commands/set-map-center.command.d.ts +18 -0
  41. package/dist/map/messages/index.d.ts +3 -0
  42. package/dist/map/models/index.d.ts +1 -0
  43. package/dist/map/models/map-control.d.ts +13 -0
  44. package/dist/map/services/controls/controls.service.d.ts +14 -0
  45. package/dist/map/services/map-state.service.d.ts +2 -0
  46. package/dist/map/services/message-registrator.service.d.ts +2 -1
  47. package/dist/src/map/map-plate/layers/feature-layer/feature-layer.settings.d.ts +46 -0
  48. package/dist/src/map/messages/commands/add-control.command.d.ts +8 -0
  49. package/dist/src/map/messages/commands/remove-control.command.d.ts +8 -0
  50. package/dist/src/map/messages/commands/set-map-center.command.d.ts +18 -0
  51. package/dist/src/map/messages/index.d.ts +3 -0
  52. package/dist/src/map/models/index.d.ts +1 -0
  53. package/dist/src/map/models/map-control.d.ts +13 -0
  54. package/dist/src/map/services/controls/controls.service.d.ts +14 -0
  55. package/dist/src/map/services/map-state.service.d.ts +2 -0
  56. package/dist/src/map/services/message-registrator.service.d.ts +2 -1
  57. package/package.json +1 -1
@@ -6,11 +6,11 @@ import { Feature, Collection } from 'ol';
6
6
  import { Point, LineString } from 'ol/geom';
7
7
  import { GeoJSON, WKT } from 'ol/format';
8
8
  import { getCenter, createEmpty, extend } from 'ol/extent';
9
+ import { Control, Zoom } from 'ol/control';
9
10
  import { get, useGeographic, transform } from 'ol/proj';
10
11
  import { PostboyGenericMessage, PostboyCallbackMessage, PostboyExecutor, PostboyService, PostboyAbstractRegistrator } from '@artstesh/postboy';
11
12
  import { Draw, Modify, Translate } from 'ol/interaction';
12
13
  import { createRegularPolygon, createBox } from 'ol/interaction/Draw';
13
- import { Zoom } from 'ol/control';
14
14
  import { first, filter, auditTime } from 'rxjs/operators';
15
15
  import { Vector, XYZ } from 'ol/source';
16
16
  import TileLayer from 'ol/layer/Tile';
@@ -246,6 +246,20 @@ class Dictionary {
246
246
  }
247
247
  }
248
248
 
249
+ /**
250
+ *
251
+ * A control is a visible widget with a DOM element in a fixed position on the screen. They can involve user input (buttons), or be informational only; the position is determined using CSS. By default these are placed in the container with CSS class name ol-overlaycontainer-stopevent, but can use any outside DOM element.
252
+ * This is the base class for controls. You can use it for simple custom controls by creating the element with listeners, creating an instance:
253
+ * var myControl = new Control({element: myElement}); and then adding this to the map.
254
+ * The main advantage of having this as a control rather than a simple separate DOM element is that preventing propagation is handled for you. Controls will also be objects in a module:ol/Collection~Collection, so you can use their methods.
255
+ * You can also extend this base for your own control class. See examples/custom-controls for an example of how to do this.
256
+ */
257
+ class MapControl extends Control {
258
+ constructor(options) {
259
+ super(options);
260
+ }
261
+ }
262
+
249
263
  class MapRenderedEvent extends PostboyGenericMessage {
250
264
  constructor(map) {
251
265
  super();
@@ -346,6 +360,50 @@ class CancelFeatureModificationCommand extends PostboyGenericMessage {
346
360
  }
347
361
  CancelFeatureModificationCommand.ID = '9c9fb40f-ea95-4704-8177-0e9ecabf36fa';
348
362
 
363
+ class AddControlCommand extends PostboyGenericMessage {
364
+ constructor(item) {
365
+ super();
366
+ this.item = item;
367
+ }
368
+ get id() {
369
+ return AddControlCommand.ID;
370
+ }
371
+ }
372
+ AddControlCommand.ID = '8e1c06eb-b395-4fe1-929c-ebf0805eeb49';
373
+
374
+ class RemoveControlCommand extends PostboyGenericMessage {
375
+ constructor(item) {
376
+ super();
377
+ this.item = item;
378
+ }
379
+ get id() {
380
+ return RemoveControlCommand.ID;
381
+ }
382
+ }
383
+ RemoveControlCommand.ID = '361641e0-804a-4930-8c27-0cea6330dbfc';
384
+
385
+ /**
386
+ * Forces map to move to a specific point
387
+ */
388
+ class SetMapCenterCommand extends PostboyGenericMessage {
389
+ /**
390
+ *
391
+ * @param lat - the desired latitude
392
+ * @param lng - the desired longitude
393
+ * @param zoom - the desired zoom; doesn't change zoom if undefined
394
+ */
395
+ constructor(lat, lng, zoom) {
396
+ super();
397
+ this.lat = lat;
398
+ this.lng = lng;
399
+ this.zoom = zoom;
400
+ }
401
+ get id() {
402
+ return SetMapCenterCommand.ID;
403
+ }
404
+ }
405
+ SetMapCenterCommand.ID = 'd50e89c9-6707-4f8c-ab57-65fcef232182';
406
+
349
407
  class AddLayerCommand extends PostboyGenericMessage {
350
408
  constructor(layer) {
351
409
  super();
@@ -598,7 +656,7 @@ class MapManagementService {
598
656
  if (!!source['getSource'])
599
657
  source = source?.getSource();
600
658
  source?.clear();
601
- source?.addFeatures(c.features);
659
+ !!c.features?.length && source?.addFeatures(c.features);
602
660
  });
603
661
  }
604
662
  observeRemoveLayer() {
@@ -637,7 +695,14 @@ class MapStateService {
637
695
  this.postboy = postboy;
638
696
  }
639
697
  up() {
640
- this.postboy.subscribe(MapRenderedEvent.ID).subscribe((ev) => {
698
+ this.observeMapRendering();
699
+ this.observeCenter();
700
+ }
701
+ observeMapRendering() {
702
+ this.postboy
703
+ .subscribe(MapRenderedEvent.ID)
704
+ .pipe(first())
705
+ .subscribe((ev) => {
641
706
  this.map = ev.map;
642
707
  this.map?.on('moveend', () => {
643
708
  const zoom = Math.floor(this.map?.getView().getZoom() || -1);
@@ -646,6 +711,13 @@ class MapStateService {
646
711
  });
647
712
  });
648
713
  }
714
+ observeCenter() {
715
+ this.postboy.subscribe(SetMapCenterCommand.ID).subscribe((c) => {
716
+ this.map?.getView().setCenter([c.lng, c.lat]);
717
+ if (c.zoom)
718
+ this.map?.getView().setZoom(c.zoom);
719
+ });
720
+ }
649
721
  }
650
722
  MapStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MapStateService, deps: [{ token: MapPostboyService }], target: i0.ɵɵFactoryTarget.Injectable });
651
723
  MapStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MapStateService });
@@ -900,14 +972,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
900
972
  type: Injectable
901
973
  }], ctorParameters: function () { return [{ type: MapPostboyService }]; } });
902
974
 
975
+ class ControlsService {
976
+ constructor(postboy) {
977
+ this.postboy = postboy;
978
+ }
979
+ up() {
980
+ this.observeMapRender();
981
+ }
982
+ observeMapRender() {
983
+ this.postboy
984
+ .subscribe(MapRenderedEvent.ID)
985
+ .pipe(first())
986
+ .subscribe((m) => {
987
+ this.map = m.map;
988
+ this.observeAdding();
989
+ this.observeRemoving();
990
+ });
991
+ }
992
+ observeAdding() {
993
+ this.postboy.subscribe(AddControlCommand.ID).subscribe((c) => this.map?.addControl(c.item));
994
+ }
995
+ observeRemoving() {
996
+ this.postboy
997
+ .subscribe(RemoveControlCommand.ID)
998
+ .subscribe((c) => this.map?.removeControl(c.item));
999
+ }
1000
+ }
1001
+ ControlsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ControlsService, deps: [{ token: MapPostboyService }], target: i0.ɵɵFactoryTarget.Injectable });
1002
+ ControlsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ControlsService });
1003
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ControlsService, decorators: [{
1004
+ type: Injectable
1005
+ }], ctorParameters: function () { return [{ type: MapPostboyService }]; } });
1006
+
903
1007
  class MessageRegistratorService extends PostboyAbstractRegistrator {
904
- constructor(service, management, state, mapFeature, interaction, drawing, featureModification) {
1008
+ constructor(service, management, state, mapFeature, interaction, drawing, featureModification, controls) {
905
1009
  super(service);
906
- this.registerServices([management, state, interaction, mapFeature, drawing, featureModification]);
1010
+ this.registerServices([management, state, interaction, mapFeature, drawing, featureModification, controls]);
907
1011
  }
908
1012
  _up() {
909
1013
  this.registerReplay(MapRenderedEvent.ID);
910
1014
  this.registerReplay(PlaceLayerFeaturesCommand.ID);
1015
+ this.registerReplay(RemoveControlCommand.ID);
1016
+ this.registerReplay(AddControlCommand.ID);
1017
+ this.registerReplay(SetMapCenterCommand.ID);
911
1018
  this.registerSubject(AddLayerCommand.ID);
912
1019
  this.registerSubject(RemoveLayerCommand.ID);
913
1020
  this.registerSubject(AddTileCommand.ID);
@@ -932,11 +1039,11 @@ class MessageRegistratorService extends PostboyAbstractRegistrator {
932
1039
  this.registerExecutor(GenerateZoomControlExecutor.ID, (e) => ZoomControlFactory.build(e.settings));
933
1040
  }
934
1041
  }
935
- MessageRegistratorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MessageRegistratorService, deps: [{ token: MapPostboyService }, { token: MapManagementService }, { token: MapStateService }, { token: MapFeatureService }, { token: MapClickService }, { token: DrawingService }, { token: FeatureModificationService }], target: i0.ɵɵFactoryTarget.Injectable });
1042
+ MessageRegistratorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MessageRegistratorService, deps: [{ token: MapPostboyService }, { token: MapManagementService }, { token: MapStateService }, { token: MapFeatureService }, { token: MapClickService }, { token: DrawingService }, { token: FeatureModificationService }, { token: ControlsService }], target: i0.ɵɵFactoryTarget.Injectable });
936
1043
  MessageRegistratorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MessageRegistratorService });
937
1044
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MessageRegistratorService, decorators: [{
938
1045
  type: Injectable
939
- }], ctorParameters: function () { return [{ type: MapPostboyService }, { type: MapManagementService }, { type: MapStateService }, { type: MapFeatureService }, { type: MapClickService }, { type: DrawingService }, { type: FeatureModificationService }]; } });
1046
+ }], ctorParameters: function () { return [{ type: MapPostboyService }, { type: MapManagementService }, { type: MapStateService }, { type: MapFeatureService }, { type: MapClickService }, { type: DrawingService }, { type: FeatureModificationService }, { type: ControlsService }]; } });
940
1047
 
941
1048
  class TileLayerSettings {
942
1049
  constructor() {
@@ -1119,13 +1226,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1119
1226
  type: Input
1120
1227
  }] } });
1121
1228
 
1229
+ /**
1230
+ * A layer that is responsible for showing and styling main features on the map, such as markers and polygons
1231
+ */
1122
1232
  class FeatureLayerSettings {
1123
1233
  constructor() {
1234
+ /**
1235
+ * The identifier of the field, it is autogenerated by default, but can be set manually
1236
+ */
1124
1237
  this.name = IdGenerator.get();
1238
+ /**
1239
+ * The priority of showing - layers with higher zIndex cover others in case of collisions
1240
+ */
1125
1241
  this.zIndex = 1;
1242
+ /**
1243
+ * The maximum zoom at which the layer is visible. 19 by default
1244
+ */
1126
1245
  this.maxZoom = 19;
1246
+ /**
1247
+ * The minimum zoom at which the layer is visible. 0 by default
1248
+ */
1127
1249
  this.minZoom = 0;
1128
1250
  }
1251
+ /**
1252
+ * Creates a clone of the existing settings
1253
+ * @param model
1254
+ */
1129
1255
  static copy(model) {
1130
1256
  const result = new FeatureLayerSettings();
1131
1257
  result.name = model.name;
@@ -1135,21 +1261,45 @@ class FeatureLayerSettings {
1135
1261
  result.style = model.style;
1136
1262
  return result;
1137
1263
  }
1264
+ /**
1265
+ Setter for {@link FeatureLayerSettings.zIndex}
1266
+ * @param zIndex
1267
+ */
1138
1268
  setZIndex(zIndex) {
1139
1269
  return FeatureLayerSettings.copy({ ...this, zIndex });
1140
1270
  }
1271
+ /**
1272
+ * Setter for {@link FeatureLayerSettings.name}
1273
+ * @param name
1274
+ */
1141
1275
  setName(name) {
1142
1276
  return FeatureLayerSettings.copy({ ...this, name });
1143
1277
  }
1278
+ /**
1279
+ * Setter for {@link FeatureLayerSettings.maxZoom}
1280
+ * @param maxZoom
1281
+ */
1144
1282
  setMaxZoom(maxZoom) {
1145
1283
  return FeatureLayerSettings.copy({ ...this, maxZoom });
1146
1284
  }
1285
+ /**
1286
+ * Setter for {@link FeatureLayerSettings.minZoom}
1287
+ * @param minZoom
1288
+ */
1147
1289
  setMinZoom(minZoom) {
1148
1290
  return FeatureLayerSettings.copy({ ...this, minZoom });
1149
1291
  }
1292
+ /**
1293
+ * Setter for {@link FeatureLayerSettings.style}
1294
+ * @param style
1295
+ */
1150
1296
  setStyle(style) {
1151
1297
  return FeatureLayerSettings.copy({ ...this, style });
1152
1298
  }
1299
+ /**
1300
+ * Checks if the model has the same content
1301
+ * @param model - the object to compare
1302
+ */
1153
1303
  isSame(model) {
1154
1304
  if (this.maxZoom !== model.maxZoom)
1155
1305
  return false;
@@ -1491,6 +1641,7 @@ MapPlateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", vers
1491
1641
  DrawingGenerationService,
1492
1642
  FeatureService,
1493
1643
  FeatureModificationService,
1644
+ ControlsService,
1494
1645
  ], usesInheritance: true, ngImport: i0, template: "<ng-content></ng-content>\r\n<art-osm-tile-layer *ngIf=\"osmUrl && map\" [map]=\"map\" [url]=\"osmUrl\"></art-osm-tile-layer>\r\n<art-feature-layer *ngIf=\"map\" [settings]=\"drawingLayerSettings\"></art-feature-layer>\r\n", styles: ["art-map-plate{position:relative;display:flex;flex-direction:column;height:100%}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: OsmTileLayerComponent, selector: "art-osm-tile-layer", inputs: ["url", "map"] }, { kind: "component", type: FeatureLayerComponent, selector: "art-feature-layer", inputs: ["settings"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1495
1646
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MapPlateComponent, decorators: [{
1496
1647
  type: Component,
@@ -1504,6 +1655,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1504
1655
  DrawingGenerationService,
1505
1656
  FeatureService,
1506
1657
  FeatureModificationService,
1658
+ ControlsService,
1507
1659
  ], template: "<ng-content></ng-content>\r\n<art-osm-tile-layer *ngIf=\"osmUrl && map\" [map]=\"map\" [url]=\"osmUrl\"></art-osm-tile-layer>\r\n<art-feature-layer *ngIf=\"map\" [settings]=\"drawingLayerSettings\"></art-feature-layer>\r\n", styles: ["art-map-plate{position:relative;display:flex;flex-direction:column;height:100%}\n"] }]
1508
1660
  }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: MapPostboyService }, { type: MapPlateFactory }, { type: MessageRegistratorService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { settings: [{
1509
1661
  type: Input
@@ -1517,7 +1669,7 @@ class MarkersComponent extends DestructibleComponent {
1517
1669
  this._markers = [];
1518
1670
  }
1519
1671
  set markers(value) {
1520
- this._markers = value;
1672
+ this._markers = value ?? [];
1521
1673
  this.putMarkers();
1522
1674
  }
1523
1675
  ngOnInit() {
@@ -1527,7 +1679,7 @@ class MarkersComponent extends DestructibleComponent {
1527
1679
  .subscribe(() => this.putMarkers());
1528
1680
  }
1529
1681
  putMarkers() {
1530
- if (!this._markers?.length)
1682
+ if (!this._markers)
1531
1683
  return;
1532
1684
  this.postboy.fire(new PlaceLayerFeaturesCommand(this.layerName, this._markers.map((m) => m.feature)));
1533
1685
  }
@@ -1647,7 +1799,7 @@ class PolygonsComponent extends DestructibleComponent {
1647
1799
  this._polygons = [];
1648
1800
  }
1649
1801
  set polygons(value) {
1650
- this._polygons = value;
1802
+ this._polygons = value ?? [];
1651
1803
  this.putPolygons();
1652
1804
  }
1653
1805
  ngOnInit() {
@@ -1945,5 +2097,5 @@ class StringifyFeatureHelper {
1945
2097
  * Generated bundle index. Do not edit.
1946
2098
  */
1947
2099
 
1948
- export { CancelDrawingCommand, CancelFeatureModificationCommand, CloseTooltipCommand, ClusterLayerComponent, ClusterLayerSettings, Dictionary, DrawSelectionAreaCommand, DrawingType, FeatureLayerComponent, FeatureLayerSettings, FeatureOutputFormat, MapClickEvent, MapControlZoomComponent, MapLyrs, MapLyrsLabel, MapModule, MapMoveEndEvent, MapPlateComponent, MapPostboyService, MapRenderedEvent, MapSettings, MarkerModel, MarkerStyleHelper, MarkersComponent, MessageRegistratorService, ModifyFeatureCommand, OsmTileLayerComponent, PolygonModel, PolygonStyleHelper, PolygonsComponent, StartDrawingCommand, StringifyFeatureHelper, TextStyleHelper, TileLayerComponent, TileLayerSettings, TooltipComponent, TooltipSettings, ZoomControlSettings };
2100
+ export { AddControlCommand, CancelDrawingCommand, CancelFeatureModificationCommand, CloseTooltipCommand, ClusterLayerComponent, ClusterLayerSettings, Dictionary, DrawSelectionAreaCommand, DrawingType, FeatureLayerComponent, FeatureLayerSettings, FeatureOutputFormat, MapClickEvent, MapControl, MapControlZoomComponent, MapLyrs, MapLyrsLabel, MapModule, MapMoveEndEvent, MapPlateComponent, MapPostboyService, MapRenderedEvent, MapSettings, MarkerModel, MarkerStyleHelper, MarkersComponent, MessageRegistratorService, ModifyFeatureCommand, OsmTileLayerComponent, PolygonModel, PolygonStyleHelper, PolygonsComponent, RemoveControlCommand, SetMapCenterCommand, StartDrawingCommand, StringifyFeatureHelper, TextStyleHelper, TileLayerComponent, TileLayerSettings, TooltipComponent, TooltipSettings, ZoomControlSettings };
1949
2101
  //# sourceMappingURL=maps-components.mjs.map