[GIS] OpenLayers and proj4js.defs() – why does one custom projection work and not the other

javascriptopenlayersprojproj4js

The javascript at https://jsfiddle.net/nsands/kvhcuL72/ is the simplest demonstration I've come up with for this issue. It is based on OpenLayers example code, but I've defined the map projection using proj4js.

It works fine for my custom EPSG:28355 projection, but it does not work for my custom EPSG:4326 projection, which results in an empty map. The projection is correct according to https://epsg.io/4326.

Below are the two proj4.defs() lines from the jsfiddle.

This first one works fine and OpenLayers reprojects (warps) the OSM map (EPSG:3857) to EPSG:28355 no problems:

//  EPSG:28355
proj4.defs('BLAH', '+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs');

(It does take a little time for the map to appear, as warping rasters is not a super-fast process.)

This second one does not work and results in an empty white map:

//  EPSG:4326
proj4.defs('BLAH', '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');

If I use the already built-in EPSG:4326, instead of my own custom defined one, it also works just fine and reprojects the map perfectly. In the jsfiddle, this can be tested by changing which of the projection: lines is uncommented in the map's view definition.

Why does my custom definition of EPSG:4326 not work in my OpenLayers code, even though the built in EPSG:4326 and my custom EPSG:28355 both work fine?

I assume I'm using the libraries incorrectly, or perhaps assuming functionality that does not exist. But from the documentation I've seen, I had expected it to work.

(I'm using a custom definition of EPSG:4326 because in my real OpenLayers app, the projection is determined at run-time and the EPSG code may not be available, even then – only the proj4 string. Therefore I cannot hard-code the projection in the javascript, and I need to be able to work without an EPSG code. It needs to work for whatever projection is passed in, including the proj4 string for EPSG:4326.)

UPDATE – Documentation:

I had been under the impression that OpenLayers could simply use proj4js defined projections. Although the OL documentation is not entirely clear on this, I had got this impression from several 3rd party examples, from the snippets of OpenLayers documentation below, AND because it appears to work fine in my JSFiddle linked in the first line of this post above.

From the OpenLayers Example's comments in the code at https://openlayers.org/en/latest/examples/wms-image-custom-proj.html :

If you use Proj4js only to transform coordinates, you don't even need to create an ol.proj.Projection instance. ol.proj.get() will take care of it internally.

From the OpenLayers API documentation at https://openlayers.org/en/latest/apidoc/ol.proj.html :

[OpenLayers] will check if the Proj4js library and the necessary definition are loaded; if so, it will register the appropriate ol.proj.Projection object and add transform functions between the new projection and all the existing ones.

From the OpenLayers API documentation at https://openlayers.org/en/latest/apidoc/ol.proj.Projection.html :

You can use [ol.proj.Projections] in applications, but this is not required, as API params and options use ol.ProjectionLike which means the simple string code will suffice. … If you use proj4js, aliases can be added using proj4.defs()

Best Answer

Edit:

You have to add a new ol.proj.Projection in order to use your custom projection, you can't just use the proj4js-name or variable you gave your projection as an OpenLayers projection.

Make sure your new OL-projection has a correct extent and make sure you use a correct center in ol.View (depending on what your projection is).

projCode = 'BLAH';

// EPSG:4326
proj4.defs(projCode, '+proj=longlat +datum=WGS84 +no_defs');

var myProjection = new ol.proj.Projection({
    code: projCode,
    extent: [-170.0, -80.0, 170.0, 80.0]
  });

And later:

var map = new ol.Map({
    layers: layers,
    target: 'map',
    view: new ol.View({
      projection: myProjection,
      center: [0, 0]
      zoom: 2
    })
  });

See working example: https://jsfiddle.net/kvhcuL72/17/

Related Question