Вы находитесь на странице: 1из 24

Introduction

Objectives
With version 3, the OpenLayers web mapping library was fundamentally redesigned.
The widely used version 2 dates from the early days of Javascript development, and
was increasingly showing its age. So it has been rewritten from the ground up to use
modern design patterns.
The initial release aims to support much of the functionality provided by version 2,
with support for a wide range of commercial and free tile sources, and the most
popular open-source vector data formats. As with version 2, data can be in any
projection. The initial release also adds some additional functionality, such as the
ability to easily rotate or animate maps.
It is also designed such that major new features, such as displaying 3D maps, or
using WebGL to quickly display large vector data sets, can be added in later
releases.

Google Closure
OpenLayers was written in a way so it can be compiled with Closure Compiler. Its
'advanced' compilation mode offers a level of compression that exceeds anything
else available.

Public API
Using the advanced optimizations of the Closure Compiler means that properties and
methods are renamed longMeaningfulName might become xB and so are
effectively unusable in applications using the library. To be usable, they have to be
explicitly exported. This means the exported names, those not renamed, effectively
become the public API of the library. These exportable properties and methods are
marked in the source, and documented in the API docs. This is the officially
supported API of the library. A build containing all these exportable names is known
as a full build. A hosted version of this is available, which can be used by any
application.

Custom Builds
Unlike in, say, Node, where a module's exports are fixed in the source, with Closure
Compiler, exports can be defined at compile time. This makes it easy to create builds
that are customized to the needs of a particular site or application: a custom
build only exports those properties and methods needed by the site or application.
As the full build is large, and will probably become larger as new features are added
to the API, it's recommended that sites create a custom build for production software.

Renderers and Browser Support


The library currently includes two renderers: Canvas and WebGL. Both of them
support both raster data from tile/image servers, and vector data; WebGL however
does not support labels. Clearly only those browsers that support Canvas can use
the Canvas renderer. Equally, the WebGL renderer can only be used on those
devices and browsers that support WebGL.
OpenLayers runs on all modern browsers that support HTML5 and ECMAScript 5.
This includes Chrome, Firefox, Safari and Edge. For older browsers and platforms
like Internet Explorer (down to version 9) and Android
4.x, polyfills for requestAnimationFrame and Element.prototype.classList are
required, and using the KML format requires a polyfill for URL.
The library is intended for use on both desktop/laptop and mobile devices.

Objects and Naming Conventions


The top-level namespace is ol (basically, var ol = {};). Subdivisions of this are:

further namespaces, such as ol.layer; these have a lower-case initial


simple objects containing static properties and methods, such as ol.easing;
these also have a lower-case initial
types, which have an upper-case initial. These are mainly 'classes', which
here means a constructor function with prototypal inheritance, such
as ol.Map or ol.layer.Vector (the Vector class within the layer namespace).
There are however other, simpler, types, such as ol.Extent, which is an
array.

Class namespaces, such as ol.layer have a base class type with the same name,
such as ol.layer.Layer. These are mainly abstract classes, from which the other
subclasses inherit.
Source files are similarly organised, with a directory for each class namespace.
Names are however all lower-case, for example, ol/layer/vector.js.
OpenLayers follows the convention that the names of private properties and
methods, that is, those that are not part of the API, end in an underscore. In general,
instance properties are private and accessed using accessors.

Basic Concepts
Map
The core component of OpenLayers is the map (ol.Map). It is rendered to
a target container (e.g. a div element on the web page that contains the map). All
map properties can either be configured at construction time, or by using setter
methods, e.g. setTarget().

<div id="map" style="width: 100%, height: 400px"></div>


<script>
var map = new ol.Map({target: 'map'});
</script>

View
ol.Map is not responsible for things like center, zoom level and projection of the map.
Instead, these are properties of an ol.View instance.

map.setView(new ol.View({
center: [0, 0],
zoom: 2
}));

An ol.View also has a projection. The projection determines the coordinate system
of the center and the units for map resolution calculations. If not specified (like in the
above snippet), the default projection is Spherical Mercator (EPSG:3857), with
meters as map units.
The zoom option is a convenient way to specify the map resolution. The available
zoom levels are determined by maxZoom (default: 28), zoomFactor (default: 2)
and maxResolution (default is calculated in such a way that the projection's validity
extent fits in a 256x256 pixel tile). Starting at zoom level 0 with a resolution
of maxResolution units per pixel, subsequent zoom levels are calculated by dividing
the previous zoom level's resolution by zoomFactor, until zoom level maxZoom is
reached.

Source
To get remote data for a layer, OpenLayers uses ol.source.Source subclasses.
These are available for free and commercial map tile services like OpenStreetMap or
Bing, for OGC sources like WMS or WMTS, and for vector data in formats like
GeoJSON or KML.

var osmSource = new ol.source.OSM();

Layer
A layer is a visual representation of data from a source. OpenLayers has three basic
types of layers: ol.layer.Tile, ol.layer.Image and ol.layer.Vector.
ol.layer.Tile is for layer sources that provide pre-rendered, tiled images in grids
that are organized by zoom levels for specific resolutions.
ol.layer.Image is for server rendered images that are available for arbitrary extents
and resolutions.
ol.layer.Vector is for vector data that is rendered client-side.

var osmLayer = new ol.layer.Tile({source: osmSource});


map.addLayer(osmLayer);

Putting it all together


The above snippets can be conflated to a self contained map configuration with view
and layers:

<div id="map" style="width: 100%, height: 400px"></div>


<script>
new ol.Map({
layers: [
new ol.layer.Tile({source: new ol.source.OSM()})
],
view: new ol.View({
center: [0, 0],
zoom: 2
}),
target: 'map'
});
</script>

Creating custom builds


OpenLayers is a big library providing a lot of functionality. So it is unlikely that an
application will need and use all the functionality OpenLayers provides. This is why
creating application-specific OpenLayers builds, with just the functionality your
application needs, is often a good idea.
An alternative to creating custom builds is to compile your application code together
with OpenLayers. See the Compiling Application with Closure Compiler tutorial for
more information.
This particular tutorial explains how to create custom builds of OpenLayers.

Requirements
OpenLayers's build tools use Node and Java, so you need to have Node and Java
installed on your machine. You can run node --version and java -version to test
that Node and Java are installed, respectively. See developing guide for minimum
version numbers required.

Download OpenLayers
Obviously, creating a custom build requires the OpenLayers source and specific build
scripts.
To get the OpenLayers source and the build scripts you can clone the
openlayers repository, or you can download one of the release archives. You can
also download the openlayers Node package from the Node package registry, using
NPM (the Node Package Manager). This is the method we are going to use in this
tutorial.
Create a directory:

$ mkdir openlayers

Download the OpenLayers distribution using NPM:

$ npm install openlayers

This will download the latest stable version of OpenLayers, and install it
under node_modules. You can list the content of node_modules to verify that it
effectively contains a directory named "openlayers".
The Node packages onto which the openlayers package depends are installed
under node_modules/openlayers/node_modules . That directory should, for example,
include closure-util, which is the utility library OpenLayers uses for Closure.
You should now have everything you need to create custom builds of OpenLayers!

Create a build configuration file


Creating a custom build requires writing a build configuration file. The format of build
configuration files is JSON. Here is a simple example of a build configuration file:

{
"exports": [
"ol.Map",
"ol.View",
"ol.control.defaults",
"ol.layer.Tile",
"ol.source.OSM"
],
"compile": {
"externs": [
"externs/bingmaps.js",
"externs/cartodb.js",
"externs/closure-compiler.js",
"externs/esrijson.js",
"externs/geojson.js",
"externs/oli.js",
"externs/olx.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"extra_annotation_name": [
"api", "observable"
],
"compilation_level": "ADVANCED",
"manage_closure_dependencies": true,
"rewrite_polyfills": false
}
}

Create a file named ol-custom.json with that content, and save it under
the node_modules/openlayers/build directory. (You can save it to any location
really.)
The most relevant part of this configuration object is the "exports" array. This array
declares the functions/constructors you use in your JavaScript code. For example,
the above configuration file is what you'd use for the following JavaScript code:

var map = new ol.Map({


target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
controls: ol.control.defaults({
attributionOptions: {
collapsible: false
}
}),
view: new ol.View({
center: [0, 0],
zoom: 4
})
});

Note that this JavaScript code corresponds to OpenLayers's simple example.


You are now ready to create your first OpenLayers build. Use the following command
to create the build:

$ cd node_modules/openlayers
$ node tasks/build.js build/ol-custom.json build/ol-custom.js

The build command may take some time, but it should end with an output in the
console such as the following:

info ol Parsing dependencies


info ol Compiling 364 sources

The build command should have created an ol-custom.js file in


the node_modules/openlayers/build directory. You can verify that the file was
created. You can even open it in your editor if you're curious.
As a test, you can use the following HTML file to verify that your custom build works
as expected:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>OpenLayers example</title>
<link rel="stylesheet" href="node_modules/openlayers/css/ol.css" />
<style>
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="node_modules/openlayers/build/ol-custom.js"></script>
<script>
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [0, 0],
zoom: 4
})
});
</script>
</body>
</html>

More on the config file


define's
Closure allows you to define constants that can be set at compile time. The
OpenLayers code defines several such values.
Setting some of these to false means that the portions of the code relating to this
setting become "dead", i.e. are never executed. As Closure
Compiler's ADVANCEDmode removes dead code, this makes the size of the advanced
compiled file smaller.
You might have noticed that the build file you've just created is considerably smaller
than the full build, but it can be reduced further. This is because both renderers and
other optional code are included by default. We only need one renderer, and we do
not use the optional code, so can exclude what we don't use by setting properties
with defines. So add a define section to the config above:

"define": [
"ol.ENABLE_WEBGL=false",
"ol.ENABLE_PROJ4JS=false",
"ol.ENABLE_RASTER_REPROJECTION=false"
],

and re-run the build script. The build size should now be smaller.

Externs
The Closure documentation explains that "externs" are for external names used in
the code being compiled. The compiler includes externs for built-ins such
as document. The externs directory of the OpenLayers code includes files for all
those used in some part of the library. For example, if you use Bing Maps, you
should include the Bing externs file in the externs section of the config file.
oli.js and olx.js are externs files for the OpenLayers API. For
example olx.js includes extern definitions for OpenLayers's constructor
options. closure-compiler.js fixes any issues that may arise with a specific compiler
version. You should always use these three files as externs when creating custom
builds.
Other compiler options
There are a couple of other compiler options in the config file
above. manage_closure_dependencies and rewrite_polyfills should always be
used.
You can specify any of the other compiler options here as needed, such as the
renaming reports, output manifest, or source maps. There is a full list of available
options in closure-util.
Note that build.js currently requires you to enter an output file and will write the
output from the compiler to it; it does not use the js_output_file compiler option. If
you specify this in the config file, there will be no compiler output, so build.js's
output file will be empty.

A more complicated example


Now let's try a more complicated example: heatmaps-earthquakes. The build
configuration file looks like this:

{
"exports": [
"ol.layer.Heatmap",
"ol.source.Vector",
"ol.format.KML",
"ol.layer.Heatmap#getSource",
"ol.source.Vector#on",
"ol.source.Vector.Event#feature",
"ol.Feature#get",
"ol.Feature#set",
"ol.layer.Tile",
"ol.source.Stamen",
"ol.Map",
"ol.View",
"ol.layer.Heatmap#setRadius",
"ol.layer.Heatmap#setBlur"
],
"compile": {
"externs": [
"externs/bingmaps.js",
"externs/cartodb.js",
"externs/closure-compiler.js",
"externs/esrijson.js",
"externs/geojson.js",
"externs/olx.js",
"externs/oli.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"define": [
"ol.ENABLE_WEBGL=false",
"ol.ENABLE_PROJ4JS=false",
"ol.ENABLE_RASTER_REPROJECTION=false"
],
"compilation_level": "ADVANCED",
"manage_closure_dependencies": true,
"rewrite_polyfills": false
}
}

The exports are given here in the order in which they occur in the heatmaps-
earthquakes example's JavaScript code. In this example we not only use
the ol.functions and constructors, but also prototype methods where
the ol namespace is not directly used. In the code, we have for
example vector.getSource().on(). This means we are using the getSource method
of layer.Heatmap and the on method of source.KML, so this is what has to be
exported. Similarly, event.feature.get() means we are using the feature property
of source.Vector.Event and the get method of Feature. If any of these names are
left out, the compile will complete successfully, but the missing names will be
obfuscated and you will get a 'property undefined' error when you try and run the
script.

Maintaining the code


If you installed OpenLayers from the Node package, you can use npm to upgrade to
the latest version. If you cloned the Github repo, simply pulling in the latest code may
not be enough, as some of the packages used, for example, the compiler, may need
upgrading too. Do this by using npm install rather than npm update.

Conclusion
This tutorial should have given you the information you need to create custom builds,
i.e. builds tailored to your application. See the tasks readme for more information on
the build scripts and the properties you can use in the build configuration file.
Code licensed under the 2-Clause BSD. All documentation C
Introduction
When going beyond modifying existing examples you might be looking for a way to
setup your own code with dependency management together with external
dependencies like OpenLayers.
This tutorial serves as a suggested project setup using NPM and Browserify for the
most basic needs. There are several other options, and in particular you might be
interested in a more modern one (ES2015) using Webpack with OpenLayers.

Initial steps
Create a new empty directory for your project and navigate to it by running mkdir
new-project && cd new-project. Initialize your project using npm init and answer
the questions asked.
Add OpenLayers as dependency to your application with npm install --save ol.
At this point you can ask NPM to add required development dependencies by
running

npm install --save-dev cssify browserify cssify http-server uglify-js


watchify
npm install --save-dev babelify babel-plugin-transform-es2015-modules-
commonjs

We will be using cssify to include the css definitions required by OpenLayers in our
bundle. watchify, http-server and uglify-js are used to monitor for changes and
to build into a minified bundle. babelify and babel-plugin-transform-es2015-
modules-commonjs are used to make the ol package, which was created using
ES2015 modules, work with CommonJS.

Application code and index.html


Place your application code in index.js. Here is a simple starting point:

require('ol/ol.css');
var ol_Map = require('ol/map').default;
var ol_layer_Tile = require('ol/layer/tile').default;
var ol_source_OSM = require('ol/source/osm').default;
var ol_View = require('ol/view').default;

var map = new ol_Map({


target: 'map',
layers: [
new ol_layer_Tile({
source: new ol_source_OSM()
})
],
view: new ol_View({
center: [0, 0],
zoom: 0
})
});

You will also need an ndex.html file that will use your bundle. Here is a simple
example:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Using Browserify with OpenLayers</title>
<style>
#map {
width: 400px;
height: 250px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="bundle.js"></script>
</body>
</html>

Creating a bundle
With simple scripts you can introduce the commands npm run build and npm
start to manually build your bundle and watch for changes, respectively. Add the
following to the script section in package.json:

"scripts": {
"start": "watchify index.js -g cssify --outfile bundle.js & http-server",
"build": "browserify -g cssify index.js | uglifyjs --compress --output
bundle.js"
}
Now to test your application open http://localhost:8080/ in your browser. watchify will
update bundle.js whenever you change something. You simply need to reload the
page in your browser to see the changes.

$ npm start

Note that bundle.js will contain your application code and all dependencies used in
your application. From OpenLayers, it only contains the required components.

Compiling Application with Closure


Compiler
Note: When building an application with dependencies that are available
as npm packages, it will probably be easier to use the ol package and follow the
instructions there.
The OpenLayers code uses the Closure Library, and it is compiled with the Closure
Compiler. Using OpenLayers in an application does not require using Closure. But
using Closure in an OpenLayers application is possible. And this is what this tutorial
is about.
When you want to include OpenLayers as separate script without bundling with your
application, follow the Creating custom builds tutorial instead.
This tutorial will teach you how to set up an OpenLayers application based on
the closure-util node package, which provides utilities for working with Closure.
Using closure-util is one way to use Closure in a web application, but there are
others. This tutorial just covers the "closure-util" way.
The closure-util documentation is available on the closure-util readme page.
You don't need to read the closure-util documentation to follow this tutorial, but it's
available in closure-util's readme file if you need it.
Also, the sample application built in this tutorial is available on GitHub.

Advantages of using Closure


This tutorial will show you how to use the Closure Compiler to compile an application
and OpenLayers together. Compiling the application code together with the
OpenLayers code has a number of advantages.
First of all, it allows you to only "pay" for the OpenLayers code your application uses,
as the compiler will exclude the OpenLayers code that the application doesn't use.
And there is no need to write and maintain a list of "exports", which is necessary
when creating custom builds of OpenLayers.
Also, compiling the application and OpenLayers together allows using OpenLayers
functions and objects that are not part of the official OpenLayers 3 API. Using non-
API functions and objects may be risky, but it is mitigated by the fact that the
compiler will complain if you use functions or objects that are not in OpenLayers
anymore.
Setting up the Application
First, create a directory for the application. We will name that directory openlayers-
closure-application in this tutorial.

$ mkdir openlayers-closure-application

Now change to that directory:

$ cd openlayers-closure-application

Our application will be a node application, and the openlayers and closure-
util node packages will be downloaded from the node package registry using
the npm command line tool.
So we're going to create a package.json file for the application, which every node
application includes. This file basically includes metadata for the application.
Create the application's package.json file:

$ npm init

You can pretty much use the default answers to the questions npm init asks you.
Now install OpenLayers using:

$ npm install openlayers --save

The --save flag persists the openlayers dependency in the


application's package.json file. You can edit package.json to verify that the
dependency was added.
closure-util is a dependency of the openlayers package, so it should have been
installed with openlayers. Use the following to verify that closure-util is installed:

$ ./node_modules/openlayers/node_modules/.bin/closure-util

command argument is required

Usage: node closure-util <command> [options]

command
update-compiler Update the Compiler
update-library Update the Library
update Update both the Library and the Compiler
build Build with Closure Compiler
serve Start the development server

Options:
-l LEVEL, --loglevel LEVEL Log level [info]

Create an OpenLayers map


You're now going to create a JavaScript file that creates an OpenLayers map. This is
the file that we will define the application's entry point.
First of all create an src directory at the root of the application:

$ mkdir src

Now add a file main.js to src, with the following content:

goog.provide('app');

goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
goog.require('ol.source.OSM');

/**
* @type {ol.Map}
*/
app.map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: [0, 0],
zoom: 4
})
});

goog.provide('app') creates the namespace app for the application.


The goog.require statements that follow define the OpenLayers constructors and
namespaces that the application uses. The rest of the code just creates the
OpenLayers map as you would do in any OpenLayers application.
Compiling the Application
We're now going to compile the application and OpenLayers together, using the
Closure Compiler and closure-util. For this we need to create a JSON config file,
that we will then pass as an input file to the closure-util command.
The minimum config file looks like this:

{
"lib": [
"node_modules/openlayers/src/**/*.js",
"node_modules/openlayers/build/ol.ext/**/*.js",
"src/**/*.js"
],
"compile": {
"closure_entry_point": "app",
"externs": [
"node_modules/openlayers/externs/bingmaps.js",
"node_modules/openlayers/externs/cartodb.js",
"node_modules/openlayers/externs/closure-compiler.js",
"node_modules/openlayers/externs/esrijson.js",
"node_modules/openlayers/externs/geojson.js",
"node_modules/openlayers/externs/proj4js.js",
"node_modules/openlayers/externs/tilejson.js",
"node_modules/openlayers/externs/topojson.js"
],
"define": [
"ol.ENABLE_WEBGL=false"
],
"js": [
"node_modules/openlayers/src/ol/typedefs.js",
"node_modules/openlayers/externs/olx.js",
"node_modules/openlayers/externs/oli.js"
],
"extra_annotation_name": [
"api", "observable"
],
"rewrite_polyfills": "false",
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true
}
}

Create a config.json file with the above content at the root of the application
directory.
We can now use closure-util to compile the code:

$ ./node_modules/openlayers/node_modules/.bin/closure-util build
config.json app.js

The resulting app.js file, which you can view in your editor if you're curious, includes
a minified version of the application code (main.js), and the OpenLayers code that
the application code uses.
Here is a version of config.json with more compilation checks enabled:

{
"lib": [
"node_modules/openlayers/src/**/*.js",
"node_modules/openlayers/build/ol.ext/**/*.js",
"src/**/*.js"
],
"compile": {
"closure_entry_point": "app",
"externs": [
"node_modules/openlayers/externs/bingmaps.js",
"node_modules/openlayers/externs/cartodb.js",
"node_modules/openlayers/externs/closure-compiler.js",
"node_modules/openlayers/externs/esrijson.js",
"node_modules/openlayers/externs/geojson.js",
"node_modules/openlayers/externs/proj4js.js",
"node_modules/openlayers/externs/tilejson.js",
"node_modules/openlayers/externs/topojson.js"
],
"define": [
"ol.ENABLE_WEBGL=false"
],
"js": [
"node_modules/openlayers/src/ol/typedefs.js",
"node_modules/openlayers/externs/olx.js",
"node_modules/openlayers/externs/oli.js"
],
"jscomp_error": [
"*"
],
"jscomp_off": [
"unknownDefines",
"lintChecks",
"analyzerChecks"
],
"extra_annotation_name": [
"api", "observable"
],
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true
}
}

Create an HTML file for the Application


You can now go ahead and create a simple HTML for the application. Create
a index.html file with the following content at the root the application directory:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no,
width=device-width">
<link rel="stylesheet" href="node_modules/openlayers/css/ol.css"
type="text/css">
<title>Simple example</title>
<style>
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>

Note that the page includes a script tag referencing the app.js file, which is the file
resulting from the compilation.
You are done!

Run Application in Debug Mode


As a bonus, we're going to show how to use closure-util to run the application in
"debug" mode, where the original application and OpenLayers scripts are loaded one
by one in the page.
Start the closure-util development server:

$ ./node_modules/openlayers/node_modules/.bin/closure-util serve
config.json

Now change the script tag to the following in the index.html file:

<script src="@?main=src/main.js" type="text/javascript"></script>

Reload the page in your browser and you should see that scripts are now loaded
individually, making debugging much easier.

Raster Reprojection
OpenLayers has an ability to display raster data from WMS, WMTS, static images
and many other sources in a different coordinate system than delivered from the
server. Transformation of the map projections of the image happens directly in a web
browser. The view in any Proj4js supported coordinate reference system is possible
and previously incompatible layers can now be combined and overlaid.

Usage
The API usage is very simple. Just specify proper projection (using EPSG code)
on ol.View:
var map = new ol.Map({
target: 'map',
view: new ol.View({
projection: 'EPSG:3857', //HERE IS THE VIEW PROJECTION
center: [0, 0],
zoom: 2
}),
layers: [
new ol.layer.Tile({
source: new ol.source.TileWMS({
projection: 'EPSG:4326', //HERE IS THE DATA SOURCE PROJECTION
url: 'http://demo.boundlessgeo.com/geoserver/wms',
params: {
'LAYERS': 'ne:NE1_HR_LC_SR_W_DR'
}
})
})
]
});

If a source (based on ol.source.TileImage or ol.source.Image) has a projection


different from the current ol.Views projection then the reprojection happens
automatically under the hood.

Examples
Raster reprojection demo
OpenStreetMap to WGS84 reprojection
Reprojection with EPSG.io database search
Image reprojection

Custom projection
The easiest way to use a custom projection is to add the Proj4js library to your
project and then define the projection using a proj4 definition string. Following
example shows definition of a British National Grid:

<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.4/proj4.js"></scrip
t>
proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 '
+
'+x_0=400000 +y_0=-100000 +ellps=airy ' +
'+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' +
'+units=m +no_defs');
var proj27700 = ol.proj.get('EPSG:27700');
proj27700.setExtent([0, 0, 700000, 1300000]);

Change of the view projection


To switch the projection used to display the map you have to set a new ol.View with
selected projection on the ol.Map:

map.setView(new ol.View({
projection: 'EPSG:27700',
center: [400000, 650000],
zoom: 4
}));

TileGrid and Extents


When reprojection is needed, new tiles (in the target projection) are under the hood
created from the original source tiles. The TileGrid of the reprojected tiles is by
default internally constructed using ol.tilegrid.getForProjection(projection) .
The projection should have extent defined (see above) for this to work properly.
Alternatively, a custom target TileGrid can be constructed manually and set on the
source instance
using ol.source.TileImage#setTileGridForProjection(projection, tilegrid) .
This TileGrid will then be used when reprojecting to the specified projection instead
of creating the default one. In certain cases, this can be used to optimize
performance (by tweaking tile sizes) or visual quality (by specifying resolutions).

How it works
The reprojection process is based on triangles -- the target raster is divided into a
limited number of triangles with vertices transformed using ol.proj capabilities
(proj4js is usually utilized to define custom transformations). The reprojection of
pixels inside the triangle is approximated with an affine transformation (with rendering
hardware-accelerated by the canvas 2d context):
This way we can support a wide range of projections from proj4js (or even custom
transformation functions) on almost any hardware (with canvas 2d support) with a
relatively small number of actual transformation calculations.
The precision of the reprojection is then limited by the number of triangles.
The reprojection process preserves transparency on the raster data supplied from
the source (png or gif) and the gaps and no-data pixels generated by reprojection are
automatically transparent.

Dynamic triangulation
The above image above shows a noticeable error (especially on the edges) when the
original image (left; EPSG:27700) is transformed with only a limited number of
triangles (right; EPSG:3857). The error can be minimized by increasing the number
of triangles used.
Since some transformations require a more detail triangulation network, the dynamic
triangulation process automatically measures reprojection error and iteratively
subdivides to meet a specific error threshold:
For debugging, rendering of the reprojection edges can be enabled
by ol.source.TileImage#setRenderReprojectionEdges(true).

Advanced
Disabling reprojection
In case you are creating a custom build of OpenLayers and do not need the
reprojection code, you can reduce the build size by
setting ol.ENABLE_RASTER_REPROJECTION to false, which completely disables the
reprojection support. See Custom builds tutorial on how to do this.

Triangulation precision threshold


The default triangulation error threshold in pixels is given
by ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD (0.5 pixel). In case a different
threshold needs to be defined for different sources,
the reprojectionErrorThreshold option can be passed when constructing the tile
image source.

Limiting visibility of reprojected map by extent


The reprojection algorithm uses inverse transformation (from view projection to data
projection). For certain coordinate systems this can result in a "double occurrence" of
the source data on a map. For example, when reprojecting a map of Switzerland
from EPSG:21781 to EPSG:3857, it is displayed twice: once at the proper place in
Europe, but also in the Pacific Ocean near New Zealand, on the opposite side of the
globe.
Although this is mathematically correct behavior of the inverse transformation,
visibility of the layer on multiple places is not expected by users. A possible general
solution would be to calculate the forward transformation for every vertex as well -
but this would significantly decrease performance (especially for computationally
expensive transformations).
Therefore a recommended workaround is to define a proper visibility extent on
the ol.layer.Tile in the view projection. Setting such a limit is demonstrated in
the reprojection demo example.

Resolution calculation
When determining source tiles to load, the ideal source resolution needs to be
calculated. The ol.reproj.calculateSourceResolution(sourceProj, targetProj,
targetCenter, targetResolution) function calculates the ideal value in order to
achieve pixel mapping as close as possible to 1:1 during reprojection, which is then
used to select proper zoom level from the source.
It is, however, generally not practical to use the same source zoom level for the
whole target zoom level -- different projections can have significantly different
resolutions in different parts of the world (e.g. polar regions in EPSG:3857 vs
EPSG:4326) and enforcing a single resolution for the whole zoom level would result
in some tiles being scaled up/down, possibly requiring a huge number of source tiles
to be loaded. Therefore, the resolution mapping is calculated separately for each
reprojected tile (in the middle of the tile extent).