A Guide for Developers Traveling Through OpenLayers - 10. Creating an Open Street Map (OSM) Map
A Guide for Developers Traveling Through OpenLayers - 10. Creating an Open Street Map (OSM) Map
OSM is a world map that map professionals from around the world autonomously manage. In other words, it's easiest to think of it as open source for the mapping field. Contributors from each country manage the map, and each country's territory is displayed in that country's language. It has the advantage of being applicable without issue to services targeting the entire world. However, based in Korea, the quality of the map isn't all that great.
OpenLayers provides OSM by default at the library level. In other words, you can put a world map up on the web with just a few lines of simple code, without any special API calls or configuration.
This chapter covers the very basic method of putting up OSM on the web using OpenLayers6.
We mentioned this before, but just in case, let's go over the structure of OpenLayers once more.
- Feature: Elements such as points, lines, and polygons (vector layer only)
- Source: The data source of a layer. Similar to a collection of Features. (SHP, GeoJSON, etc.)
- Layer: A dataset defined based on a data source (vector, image)
- View: Information about how the user currently views the map
- Interaction: Interactive elements of the map (zoom in/out buttons, etc.)
- Overlay: Elements to display on the map
Since this chapter only needs OSM alone, the elements required are as follows.
- Source: The source of OSM
- Layer: The OSM layer defined by the OSM source
- View: View information
The remaining elements are not used, or use default values.
Let's create an OSM Source object that manages OSM data.
TYPESCRIPT
import OSM from 'ol/source/OSM'; // Default const source = new OSM(); // Applying options const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 });
| Name | Type | Default | Description |
|---|---|---|---|
| attributions | ol/source/Source-AttributionLike | undefined | Attribution text (bottom-right of map) | |
| cacheSize | number | undefined | Tile cache size | |
| crossOrigin | string | null | anonymous | CORS attribute |
| boolean | true | Deprecated attribute. Whether to use interpolation | |
| interpolate | boolean | true | Whether to use interpolation |
| maxZoom | number | 19 | Maximum zoom level. No data is shown beyond the specified zoom level |
| opaque | boolean | true | Whether it is opaque |
| reprojectionErrorThreshold | number | 0.5 | Maximum reprojection error in pixels (0 ~ 1) |
| tileLoadFunction | ol/Tile-LoadFunction | undefined | URL load function | |
| transition | number | 250 | Rendering output animation duration |
| url | string | https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png | URL pattern. Values in curly braces are automatically assigned by OL |
| wrapX | boolean | true | Whether to wrap horizontally |
| zDirection | ol/array-NearestDirectionFunction | number | 0 | Whether to use a higher or lower tile when the zoom level is a real number (e.g. 12.552) |
An OSM Source can be created via OSM. It takes an options object as a parameter.
For other options and methods you can use, check ol/source/OSM.
Create a Layer object to hold the OSM Source. This Layer will display the OSM map through the assigned OSM Source.
TYPESCRIPT
import TileLayer from 'ol/layer/Tile'; import OSM from 'ol/source/OSM'; const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 }); const layer = new TileLayer({ source: source, properties: { name: 'base-osm' }, zIndex: 1, preload: Infinity });
| Name | Type | Default | Description |
|---|---|---|---|
| className | string | ol-layer | Class name |
| opacity | number | 1 | Opacity (0 ~ 1) |
| visible | boolean | true | Whether visible |
| extent | ol/extent-Extent | undefined | The rendering extent of the layer. Data is not displayed beyond this range | |
| zIndex | number | undefined | Priority (higher is shown on top) | |
| minResolution | number | undefined | Minimum display resolution | |
| maxResolution | number | undefined | Maximum display resolution | |
| minZoom | number | undefined | Minimum display zoom level | |
| maxZoom | number | undefined | Maximum display zoom level | |
| preload | number | 0 | Preload low-resolution tiles up to the specified level (0 means unused) |
| source | ol/source/Tile-TileSource | undefined | The layer's source | |
| map | ol/PluggableMap-PluggableMap | undefined | Use this layer as an overlay in the specified Map object | |
| useInterimTilesOnError | boolean | true | Whether to use interim tiles on error |
| properties | object | undefined | Arbitrary attributes. Can be manipulated with get(), set() |
You can create a tile layer via the TileLayer object.
The source option is required; if this option is left empty, nothing appears on the layer, making the layer meaningless.
properties allows you to specify arbitrary attributes of the layer. Assigning a unique identifier to the layer as above helps with managing the layer, since it becomes troublesome to extract a layer from the Map object without a unique identifier.
For other options and methods you can use, check ol/layer/Tile.
Why a tile map of all things?
For base maps, in order to serve them quickly, the map is pre-cut by zoom level and managed as static images. Because of this, it is far more advantageous in terms of management and efficiency to cut the map into fixed-sized pieces and manage them, rather than managing it as a single monolithic image. If you were to keep that large map as a single uncut piece, the image size would be far beyond what a browser could handle.In fact, the author once did map tiling at a previous job, and the size for levels 1 through 14 amounts to terabytes. That's why it's more advantageous to break it up finely and call only the range the current user is looking at.
Create a View object that will declare the map's viewing information.
TYPESCRIPT
import View from 'ol/View'; const view = new View({ projection: 'EPSG:3857', center: [ 14135490.777017945, 4518386.883679577 ], zoom: 17 });
[ 14135490.777017945, 4518386.883679577 ] is the coordinates of Seoul City Hall expressed in EPSG:3857.
| Name | Type | Default | Description |
|---|---|---|---|
| center | ol/coordinate-Coordinate | undefined | The center of the map | |
| constrainRotation | boolean | number | true | Whether rotation is constrained. If a number, indicates the number of allowed rotation steps (if 0: 90, 180, 270, 360) |
| enableRotation | boolean | true | Whether rotation is enabled |
| extent | ol/extent-Extent | undefined | The map's viewing extent. Cannot go outside the specified range | |
| constrainOnlyCenter | boolean | false | If true, the extent restriction applies only to the View's center, not to the whole extent |
| smoothExtentConstraint | boolean | true | Whether the View can slightly exceed the extent range |
| maxResolution | number | undefined | Maximum viewing resolution. Cannot zoom in beyond the specified resolution. | |
| minResolution | number | undefined | Minimum viewing resolution. Cannot zoom out beyond the specified resolution. | |
| maxZoom | number | 28 | Maximum viewing zoom level. Cannot zoom in beyond the specified zoom level. |
| minZoom | number | 0 | Minimum viewing zoom level. Cannot zoom out beyond the specified zoom level. |
| multiWorld | boolean | false | Whether multiple worlds are used |
| constrainResolution | boolean | false | Whether only integer zoom levels are allowed |
| smoothResolutionConstraint | boolean | true | Whether to use loose zoom in/out rules |
| showFullExtent | boolean | false | Whether to display the entire configured extent |
| projection | ol/proj-ProjectionLike | EPSG:3857 | Coordinate system |
| resolution | number | undefined | Initial resolution | |
| resolutions | Array<number> | undefined | List of available resolutions (descending order). max/minResolution, max/minZoom, zoomFactor options are ignored | |
| rotation | number | 0 | Default rotation value |
| zoom | number | undefined | Default zoom level | |
| zoomFactor | number | 2 | Zoom factor |
| padding | Array<number> | [ 0, 0, 0, 0 ] | Padding |
You can declare the map's viewing information through the View object.
For the smoothResolutionConstraint option, for example, let's assume the map's size is width: 120px, height: 80px. With the default value false, the map can zoom in up to 80px at most.
However, if true, the map can zoom in up to 120px at most. In other words, this specifies whether the zoom criterion of the map is based on the shortest length or the longest length.
Create the Map object that assembles all the information to build a map.
TYPESCRIPT
import Map from 'ol/Map'; import View from 'ol/View'; import TileLayer from 'ol/layer/Tile'; import OSM from 'ol/source/OSM'; const source = new OSM({ attributions: '<p>Developed by <a href="https://itcode.dev" target="_blank">RWB</a></p>', cacheSize: 0 }); const layer = new TileLayer({ source: source, properties: { name: 'base-osm' }, zIndex: 1, preload: Infinity }); const view = new View({ projection: 'EPSG:3857', center: [ 14135490.777017945, 4518386.883679577 ], zoom: 17 }); const map = new Map({ layers: [ layer ], target: 'map', view: view });
| Name | Type | Default | Description |
|---|---|---|---|
| controls | ol/Collection-Collection<ol/control/Control-Control> | Array<ol/control/Control-Control> | undefined | ol/control/defaults | The map's control object |
| pixelRatio | number | window.devicePixelRatio | Device pixel ratio |
| interactions | ol/Collection-Collection<ol/interaction/Interaction-Interaction> | Array<ol/interaction/Interaction-Interaction> | undefined | ||
| keyboardEventTarget | HTMLElement | Document | string | undefined | Target element for keyboard events | |
| layers | Array<ol/layer/Base-BaseLayer> | ol/Collection-Collection<ol/layer/Base-BaseLayer> | ol/layer/Group-LayerGroup | undefined | List of layers. The later in the array, the higher the priority | |
| maxTilesLoading | number | 16 | Maximum number of tiles that can load simultaneously |
| moveTolerance | number | 1 | Minimum pixels the mouse must move to be recognized as a map move event |
| overlays | ol/Collection-Collection<ol/Overlay-Overlay> | Array<ol/Overlay-Overlay> | undefined | The map's overlay object | |
| target | HTMLElement | string | undefined | The DOM or DOM id where the map is displayed | |
| view | ol/View-View | Promise<ol/View-View> | undefined | The map's view object |
Assign the objects declared so far to the Map object. The declared map is displayed in the DOM specified in target.
target: map means the map is displayed in the DOM whose id is map. It doesn't have to be an id — you can also assign an HTMLElement.
You can check an example implementing this at OpenLayers6 Sandbox - OSM.
Since this is simply a page displaying an OSM map, there's not much to interact with besides viewing the map.
It would also be good to compare OSM's appearance with maps serviced domestically in Korea.
Limited to Korea, many places are missing building information, and the display of public transportation is also quite lacking. This is why it has no merit as a domestic-only service.
