|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<title>OpenLayers - Frequently Asked Questions (FAQ)</title>
|
|
|
|
|
<script>
|
|
|
|
|
var gaProperty = 'UA-2577926-1';
|
|
|
|
|
// Disable tracking if the opt-out cookie exists.
|
|
|
|
|
var disableStr = 'ga-disable-' + gaProperty;
|
|
|
|
|
if (document.cookie.indexOf(disableStr + '=true') > -1) {
|
|
|
|
|
window[disableStr] = true;
|
|
|
|
|
}
|
|
|
|
|
function gaOptout() {
|
|
|
|
|
document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
|
|
|
|
|
window[disableStr] = true;
|
|
|
|
|
}
|
|
|
|
|
function gaOptoutRevoke() {
|
|
|
|
|
document.cookie = disableStr + '=false; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
|
|
|
|
|
window[disableStr] = false;
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
|
|
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-2577926-1"></script>
|
|
|
|
|
<script>
|
|
|
|
|
window.dataLayer = window.dataLayer || [];
|
|
|
|
|
function gtag(){dataLayer.push(arguments);}
|
|
|
|
|
gtag('js', new Date());
|
|
|
|
|
gtag('config', 'UA-2577926-1', { 'anonymize_ip': true });
|
|
|
|
|
</script>
|
|
|
|
|
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css" />
|
|
|
|
|
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js"></script>
|
|
|
|
|
<script>
|
|
|
|
|
window.addEventListener("load", function() {
|
|
|
|
|
window.cookieconsent.initialise({
|
|
|
|
|
'palette': {
|
|
|
|
|
'popup': {
|
|
|
|
|
'background': '#eaf7f7',
|
|
|
|
|
'text': '#5c7291'
|
|
|
|
|
},
|
|
|
|
|
'button': {
|
|
|
|
|
'background': '#56cbdb',
|
|
|
|
|
'text': '#ffffff'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'theme': 'edgeless',
|
|
|
|
|
'type': 'opt-out',
|
|
|
|
|
'onInitialise': function (status) {
|
|
|
|
|
if (!this.hasConsented()) {
|
|
|
|
|
gaOptout()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'onStatusChange': function(status, chosenBefore) {
|
|
|
|
|
if (!this.hasConsented()) {
|
|
|
|
|
gaOptout()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'onRevokeChoice': function() {
|
|
|
|
|
gaOptoutRevoke()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
|
|
|
<link href='https://fonts.googleapis.com/css?family=Quattrocento+Sans:400,400italic,700' rel='stylesheet' type='text/css'>
|
|
|
|
|
<script src="//code.jquery.com/jquery-3.5.1.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
|
|
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
|
|
|
|
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
|
|
|
<link href='../../../assets/theme/site.css' rel='stylesheet' type='text/css'>
|
|
|
|
|
<link rel="icon" type="image/x-icon" href="../../../assets/theme/img/favicon.ico" />
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<header class="navbar navbar-expand-md navbar-dark mb-3 py-0 fixed-top" role="navigation">
|
|
|
|
|
<a href='/' class='navbar-brand'><img src='../../../assets/theme/img/logo70.png'> OpenLayers</a>
|
|
|
|
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#olmenu" aria-controls="olmenu" aria-expanded="false" aria-label="Toggle navigation">
|
|
|
|
|
<span class="navbar-toggler-icon"></span>
|
|
|
|
|
</button>
|
|
|
|
|
<!-- menu items that get hidden below 768px width -->
|
|
|
|
|
<nav class="collapse navbar-collapse" id="olmenu">
|
|
|
|
|
<ul class='nav navbar-nav ml-auto'>
|
|
|
|
|
<li class="nav-item dropdown">
|
|
|
|
|
<a class="nav-link dropdown-toggle active" href="#" id="docdropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Docs</a>
|
|
|
|
|
<div class="dropdown-menu dropdown-menu-right mb-3" aria-labelledby="docdropdown">
|
|
|
|
|
<a class="dropdown-item" href="/en/latest/doc/">Docs</a>
|
|
|
|
|
<div class="dropdown-divider"></div>
|
|
|
|
|
<a class="dropdown-item" href="/en/latest/doc/quickstart.html"><i class="fa fa-check fa-fw mr-2 fa-lg"></i>Quick Start</a>
|
|
|
|
|
<a class="dropdown-item" href="/en/latest/doc/faq.html"><i class="fa fa-question fa-fw mr-2 fa-lg"></i>FAQ</a>
|
|
|
|
|
<a class="dropdown-item" href="/en/latest/doc/tutorials/"><i class="fa fa-book fa-fw mr-2 fa-lg"></i>Tutorials</a>
|
|
|
|
|
<a class="dropdown-item" href="/workshop/"><i class="fa fa-graduation-cap fa-fw mr-2 fa-lg"></i>Workshop</a>
|
|
|
|
|
<div class="dropdown-divider"></div>
|
|
|
|
|
<a class="dropdown-item" href="https://stackoverflow.com/questions/tagged/openlayers"><i class="fa fa-stack-overflow fa-fw mr-2"></i>Ask a Question</a>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
<li class="nav-item"><a class="nav-link" href="/en/latest/examples/">Examples</a></li>
|
|
|
|
|
<li class="nav-item"><a class="nav-link" href="/en/latest/apidoc/"><i class="fa fa-sitemap mr-1"></i>API</a></li>
|
|
|
|
|
<li class="nav-item dropdown">
|
|
|
|
|
<a class="nav-link dropdown-toggle" href="#" id="codedropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Code</a>
|
|
|
|
|
<div class="dropdown-menu dropdown-menu-right mb-3" aria-labelledby="codedropdown">
|
|
|
|
|
<a class="dropdown-item" href="https://github.com/openlayers/openlayers"><i class="fa fa-github fa-fw mr-2 fa-lg"></i>Repository</a>
|
|
|
|
|
<a class="dropdown-item" href="/download/"><i class="fa fa-download fa-fw mr-2 fa-lg"></i>Download</a>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</nav>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class='container'>
|
|
|
|
|
<h1 id="frequently-asked-questions-faq-">Frequently Asked Questions (FAQ)</h1>
|
|
|
|
|
<p>Certain questions arise more often than others when users ask for help. This
|
|
|
|
|
document tries to list some of the common questions that frequently get asked,
|
|
|
|
|
e.g. on <a href="https://stackoverflow.com/questions/tagged/openlayers">Stack Overflow</a>.</p>
|
|
|
|
|
<p>If you think a question (and naturally its answer) should be added here, feel
|
|
|
|
|
free to ping us or to send a pull request enhancing this document.</p>
|
|
|
|
|
<p>Table of contents:</p>
|
|
|
|
|
<ul>
|
|
|
|
|
<li><a href="#what-projection-is-openlayers-using-">What projection is OpenLayers using?</a></li>
|
|
|
|
|
<li><a href="#how-do-i-change-the-projection-of-my-map-">How do I change the projection of my map?</a></li>
|
|
|
|
|
<li><a href="#why-is-my-map-centered-on-the-gulf-of-guinea-or-africa-the-ocean-null-island-">Why is my map centered on the gulf of guinea (or africa, the ocean, null-island)?</a></li>
|
|
|
|
|
<li><a href="#why-is-the-order-of-a-coordinate-lon-lat-and-not-lat-lon-">Why is the order of a coordinate [lon,lat], and not [lat,lon]?</a></li>
|
|
|
|
|
<li><a href="#why-aren-t-there-any-features-in-my-source-">Why aren't there any features in my source?</a></li>
|
|
|
|
|
<li><a href="#how-do-i-force-a-re-render-of-the-map-">How do I force a re-render of the map?</a></li>
|
|
|
|
|
<li><a href="#why-are-my-features-not-found-">Why are my features not found?</a></li>
|
|
|
|
|
<li><a href="#user-content-why-is-zooming-or-clicking-off-inaccurate">Why is zooming or clicking off, inaccurate?</a></li>
|
|
|
|
|
</ul>
|
|
|
|
|
<h2 id="what-projection-is-openlayers-using-">What projection is OpenLayers using?</h2>
|
|
|
|
|
<p>Every map that you'll create with OpenLayers will have a view, and every view
|
|
|
|
|
will have a projection. As the earth is three-dimensional and round but the 2D
|
|
|
|
|
view of a map isn't, we need a mathematical expression to represent it. Enter
|
|
|
|
|
projections.</p>
|
|
|
|
|
<p>There isn't only one projection, but there are many common ones. Each projection
|
|
|
|
|
has different properties, in that it accurately represents distances, angles or
|
|
|
|
|
areas. Certain projections are better suited for different regions in the world.</p>
|
|
|
|
|
<p>Back to the original question: OpenLayers is capable of dealing with most
|
|
|
|
|
projections. If you do not explicitly set one, your map is going to use our
|
|
|
|
|
default which is the Web Mercator projection (EPSG:3857). The same projection is
|
|
|
|
|
used e.g. for the maps of the OpenStreetMap-project and commercial products such
|
|
|
|
|
as Bing Maps or Google Maps.</p>
|
|
|
|
|
<p>This projection is a good choice if you want a map which shows the whole world,
|
|
|
|
|
and you may need to have this projection if you want to e.g. use the
|
|
|
|
|
OpenStreetMap or Bing tiles.</p>
|
|
|
|
|
<h2 id="how-do-i-change-the-projection-of-my-map-">How do I change the projection of my map?</h2>
|
|
|
|
|
<p>There is a good chance that you want to change the default projection of
|
|
|
|
|
OpenLayers to something more appropriate for your region or your specific data.</p>
|
|
|
|
|
<p>The projection of your map can be set through the <code>view</code>-property. Here are some
|
|
|
|
|
examples:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="comment">// OpenLayers comes with support for the World Geodetic System 1984, EPSG:4326:</span>
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
projection: <span class="string">'EPSG:4326'</span>
|
|
|
|
|
<span class="comment">// other view properties like map center etc.</span>
|
|
|
|
|
})
|
|
|
|
|
<span class="comment">// other properties for your map like layers etc.</span>
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
import proj4 from <span class="string">'proj4'</span>;
|
|
|
|
|
import {register} from <span class="string">'ol/proj/proj4'</span>;
|
|
|
|
|
import {get as getProjection} from <span class="string">'ol/proj'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="comment">// To use other projections, you have to register the projection in OpenLayers.</span>
|
|
|
|
|
<span class="comment">// This can easily be done with [http://proj4js.org/](proj4)</span>
|
|
|
|
|
<span class="comment">//</span>
|
|
|
|
|
<span class="comment">// By default OpenLayers does not know about the EPSG:21781 (Swiss) projection.</span>
|
|
|
|
|
<span class="comment">// So we create a projection instance for EPSG:21781 and pass it to</span>
|
|
|
|
|
<span class="comment">// register to make it available to the library for lookup by its</span>
|
|
|
|
|
<span class="comment">// code.</span>
|
|
|
|
|
proj4.defs(<span class="string">'EPSG:21781'</span>,
|
|
|
|
|
<span class="string">'+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 '</span> +
|
|
|
|
|
<span class="string">'+x_0=600000 +y_0=200000 +ellps=bessel '</span> +
|
|
|
|
|
<span class="string">'+towgs84=660.077,13.551,369.344,2.484,1.783,2.939,5.66 +units=m +no_defs'</span>);
|
|
|
|
|
register(proj4);
|
|
|
|
|
<span class="keyword">const</span> swissProjection = getProjection(<span class="string">'EPSG:21781'</span>);
|
|
|
|
|
|
|
|
|
|
<span class="comment">// we can now use the projection:</span>
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
projection: swissProjection
|
|
|
|
|
<span class="comment">// other view properties like map center etc.</span>
|
|
|
|
|
})
|
|
|
|
|
<span class="comment">// other properties for your map like layers etc.</span>
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>We recommend to lookup parameters of your projection (like the validity extent)
|
|
|
|
|
over at <a href="https://epsg.io/">epsg.io</a>.</p>
|
|
|
|
|
<h2 id="why-is-my-map-centered-on-the-gulf-of-guinea-or-africa-the-ocean-null-island-">Why is my map centered on the gulf of guinea (or africa, the ocean, null-island)?</h2>
|
|
|
|
|
<p>If you have set a center in your map view, but don't see a real change in visual
|
|
|
|
|
output, chances are that you have provided the coordinates of the map center in
|
|
|
|
|
the wrong (a non-matching) projection.</p>
|
|
|
|
|
<p>As the default projection in OpenLayers is Web Mercator (see above), the
|
|
|
|
|
coordinates for the center have to be provided in that projection. Chances are
|
|
|
|
|
that your map looks like this:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
import TileLayer from <span class="string">'ol/layer/Tile'</span>;
|
|
|
|
|
import OSM from <span class="string">'ol/source/OSM'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> washingtonLonLat = [-<span class="number">77.036667</span>, <span class="number">38.895</span>];
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
layers: [
|
|
|
|
|
<span class="keyword">new</span> TileLayer({
|
|
|
|
|
source: <span class="keyword">new</span> OSM()
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
target: <span class="string">'map'</span>,
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
center: washingtonLonLat,
|
|
|
|
|
zoom: <span class="number">12</span>
|
|
|
|
|
})
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>Here <code>[-77.036667, 38.895]</code> is provided as the center of the view. But as Web
|
|
|
|
|
Mercator is a metric projection, you are currently telling OpenLayers that the
|
|
|
|
|
center shall be some meters (~77m and ~39m respectively) away from <code>[0, 0]</code>. In
|
|
|
|
|
the Web Mercator projection the coordinate is right in the gulf of guinea.</p>
|
|
|
|
|
<p>The solution is easy: Provide the coordinates projected into Web Mercator.
|
|
|
|
|
OpenLayers has some helpful utility methods to assist you:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
import TileLayer from <span class="string">'ol/layer/Tile'</span>;
|
|
|
|
|
import OSM from <span class="string">'ol/source/OSM'</span>;
|
|
|
|
|
import {fromLonLat} from <span class="string">'ol/proj'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> washingtonLonLat = [-<span class="number">77.036667</span>, <span class="number">38.895</span>];
|
|
|
|
|
<span class="keyword">const</span> washingtonWebMercator = fromLonLat(washingtonLonLat);
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
layers: [
|
|
|
|
|
<span class="keyword">new</span> TileLayer({
|
|
|
|
|
source: <span class="keyword">new</span> OSM()
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
target: <span class="string">'map'</span>,
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
center: washingtonWebMercator,
|
|
|
|
|
zoom: <span class="number">8</span>
|
|
|
|
|
})
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>The method <code>fromLonLat()</code> is available from version 3.5 onwards.</p>
|
|
|
|
|
<p>If you told OpenLayers about a custom projection (see above), you can use the
|
|
|
|
|
following method to transform a coordinate from WGS84 to your projection:</p>
|
|
|
|
|
<pre><code class="language-javascript">import {transform} from <span class="string">'ol/proj'</span>;
|
|
|
|
|
<span class="comment">// assuming that OpenLayers knows about EPSG:21781, see above</span>
|
|
|
|
|
<span class="keyword">const</span> swissCoord = transform([<span class="number">8.23</span>, <span class="number">46.86</span>], <span class="string">'EPSG:4326'</span>, <span class="string">'EPSG:21781'</span>);</code></pre>
|
|
|
|
|
<h2 id="why-is-the-order-of-a-coordinate-lon-lat-and-not-lat-lon-">Why is the order of a coordinate [lon,lat], and not [lat,lon]?</h2>
|
|
|
|
|
<p>Because of two different and incompatible conventions. Latitude and longitude
|
|
|
|
|
are normally given in that order. Maps are 2D representations/projections
|
|
|
|
|
of the earth's surface, with coordinates expressed in the <code>x,y</code> grid of the
|
|
|
|
|
<a href="https://en.wikipedia.org/wiki/Cartesian_coordinate_system">Cartesian system</a>.
|
|
|
|
|
As they are by convention drawn with west on the left and north at the top,
|
|
|
|
|
this means that <code>x</code> represents longitude, and <code>y</code> latitude. As stated above,
|
|
|
|
|
OpenLayers is designed to handle all projections, but the default view is in
|
|
|
|
|
projected Cartesian coordinates. It would make no sense to have duplicate
|
|
|
|
|
functions to handle coordinates in both the Cartesian <code>x,y</code> and <code>lat,lon</code>
|
|
|
|
|
systems, so the degrees of latitude and longitude should be entered as though
|
|
|
|
|
they were Cartesian, in other words, they are <code>lon,lat</code>.</p>
|
|
|
|
|
<p>If you have difficulty remembering which way round it is, use the language code
|
|
|
|
|
for English, <code>en</code>, as a mnemonic: East before North.</p>
|
|
|
|
|
<h4 id="a-practical-example">A practical example</h4>
|
|
|
|
|
<p>So you want to center your map on a certain place on the earth and obviously you
|
|
|
|
|
need to have its coordinates for this. Let's assume you want your map centered
|
|
|
|
|
on Schladming, a beautiful place in Austria. Head over to the wikipedia
|
|
|
|
|
page for <a href="https://en.wikipedia.org/wiki/Schladming">Schladming</a>. In the top-right
|
|
|
|
|
corner there is a link to <a href="https://geohack.toolforge.org/geohack.php?pagename=Schladming&params=47_23_39_N_13_41_21_E_type:city(4565">GeoHack</a>_region:AT-6),
|
|
|
|
|
which effectively tells you the coordinates are:</p>
|
|
|
|
|
<pre><code>WGS84:
|
|
|
|
|
47° 23′ 39″ N, 13° 41′ 21″ E
|
|
|
|
|
47.394167, 13.689167</code></pre>
|
|
|
|
|
<p>So the next step would be to put the decimal coordinates into an array and use
|
|
|
|
|
it as center:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
import TileLayer from <span class="string">'ol/layer/Tile'</span>;
|
|
|
|
|
import OSM from <span class="string">'ol/source/OSM'</span>;
|
|
|
|
|
import {fromLonLat} from <span class="string">'ol/proj'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> schladming = [<span class="number">47.394167</span>, <span class="number">13.689167</span>]; <span class="comment">// caution partner, read on...</span>
|
|
|
|
|
<span class="comment">// since we are using OSM, we have to transform the coordinates...</span>
|
|
|
|
|
<span class="keyword">const</span> schladmingWebMercator = fromLonLat(schladming);
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
layers: [
|
|
|
|
|
<span class="keyword">new</span> TileLayer({
|
|
|
|
|
source: <span class="keyword">new</span> OSM()
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
target: <span class="string">'map'</span>,
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
center: schladmingWebMercator,
|
|
|
|
|
zoom: <span class="number">9</span>
|
|
|
|
|
})
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>Running the above example will possibly surprise you, since we are not centered
|
|
|
|
|
on Schladming, Austria, but instead on Abyan, a region in Yemen (possibly also a
|
|
|
|
|
nice place). So what happened?</p>
|
|
|
|
|
<p>Many people mix up the order of longitude and latitude in a coordinate array.
|
|
|
|
|
Don't worry if you get it wrong at first, many OpenLayers developers have to
|
|
|
|
|
think twice about whether to put the longitude or the latitude first when they
|
|
|
|
|
e.g. try to change the map center.</p>
|
|
|
|
|
<p>Ok, then let's flip the coordinates:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import View from <span class="string">'ol/View'</span>;
|
|
|
|
|
import TileLayer from <span class="string">'ol/layer/Tile'</span>;
|
|
|
|
|
import OSM from <span class="string">'ol/source/OSM'</span>;
|
|
|
|
|
import {fromLonLat} from <span class="string">'ol/proj'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> schladming = [<span class="number">13.689167</span>, <span class="number">47.394167</span>]; <span class="comment">// longitude first, then latitude</span>
|
|
|
|
|
<span class="comment">// since we are using OSM, we have to transform the coordinates...</span>
|
|
|
|
|
<span class="keyword">const</span> schladmingWebMercator = fromLonLat(schladming);
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
layers: [
|
|
|
|
|
<span class="keyword">new</span> TileLayer({
|
|
|
|
|
source: <span class="keyword">new</span> OSM()
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
target: <span class="string">'map'</span>,
|
|
|
|
|
view: <span class="keyword">new</span> View({
|
|
|
|
|
center: schladmingWebMercator,
|
|
|
|
|
zoom: <span class="number">9</span>
|
|
|
|
|
})
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>Schladming is now correctly displayed in the center of the map.</p>
|
|
|
|
|
<p>So when you deal with EPSG:4326 coordinates in OpenLayers, put the longitude
|
|
|
|
|
first, and then the latitude. This behaviour is the same as we had in OpenLayers
|
|
|
|
|
2, and it actually makes sense because of the natural axis order in WGS84.</p>
|
|
|
|
|
<p>If you cannot remember the correct order, just have a look at the method name
|
|
|
|
|
we used: <code>fromLonLat</code>; even there we hint that we expect longitude
|
|
|
|
|
first, and then latitude.</p>
|
|
|
|
|
<h2 id="why-aren-t-there-any-features-in-my-source-">Why aren't there any features in my source?</h2>
|
|
|
|
|
<p>Suppose you want to load a KML file and display the contained features on the
|
|
|
|
|
map. Code like the following could be used:</p>
|
|
|
|
|
<pre><code class="language-javascript">import VectorLayer from <span class="string">'ol/layer/Vector'</span>;
|
|
|
|
|
import KMLSource from <span class="string">'ol/source/KML'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> vector = <span class="keyword">new</span> VectorLayer({
|
|
|
|
|
source: <span class="keyword">new</span> KMLSource({
|
|
|
|
|
projection: <span class="string">'EPSG:3857'</span>,
|
|
|
|
|
url: <span class="string">'data/kml/2012-02-10.kml'</span>
|
|
|
|
|
})
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>You may ask yourself how many features are in that KML, and try something like
|
|
|
|
|
the following:</p>
|
|
|
|
|
<pre><code class="language-javascript">import VectorLayer from <span class="string">'ol/layer/Vector'</span>;
|
|
|
|
|
import KMLSource from <span class="string">'ol/source/KML'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> vector = <span class="keyword">new</span> VectorLayer({
|
|
|
|
|
source: <span class="keyword">new</span> KMLSource({
|
|
|
|
|
projection: <span class="string">'EPSG:3857'</span>,
|
|
|
|
|
url: <span class="string">'data/kml/2012-02-10.kml'</span>
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
<span class="keyword">const</span> numFeatures = vector.getSource().getFeatures().length;
|
|
|
|
|
console.log(<span class="string">"Count right after construction: "</span> + numFeatures);</code></pre>
|
|
|
|
|
<p>This will log a count of <code>0</code> features to be in the source. This is because the
|
|
|
|
|
loading of the KML-file will happen in an asynchronous manner. To get the count
|
|
|
|
|
as soon as possible (right after the file has been fetched and the source has
|
|
|
|
|
been populated with features), you should use an event listener function on the
|
|
|
|
|
<code>source</code>:</p>
|
|
|
|
|
<pre><code class="language-javascript">vector.getSource().on(<span class="string">'change'</span>, <span class="function"><span class="keyword">function</span><span class="params">(evt)</span>{</span>
|
|
|
|
|
<span class="keyword">const</span> source = evt.target;
|
|
|
|
|
<span class="keyword">if</span> (source.getState() === <span class="string">'ready'</span>) {
|
|
|
|
|
<span class="keyword">const</span> numFeatures = source.getFeatures().length;
|
|
|
|
|
console.log(<span class="string">"Count after change: "</span> + numFeatures);
|
|
|
|
|
}
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>This will correctly report the number of features, <code>1119</code> in that particular
|
|
|
|
|
case.</p>
|
|
|
|
|
<h2 id="how-do-i-force-a-re-render-of-the-map-">How do I force a re-render of the map?</h2>
|
|
|
|
|
<p>Usually the map is automatically re-rendered, once a source changes (for example
|
|
|
|
|
when a remote source has loaded).</p>
|
|
|
|
|
<p>If you actually want to manually trigger a rendering, you could use</p>
|
|
|
|
|
<pre><code class="language-javascript">map.render();</code></pre>
|
|
|
|
|
<p>...or its companion method</p>
|
|
|
|
|
<pre><code class="language-javascript">map.renderSync();</code></pre>
|
|
|
|
|
<h2 id="why-are-my-features-not-found-">Why are my features not found?</h2>
|
|
|
|
|
<p>You are using <code>Map#forEachFeatureAtPixel</code> or <code>Map#hasFeatureAtPixel</code>, but
|
|
|
|
|
it sometimes does not work for large icons or labels? The <em>hit detection</em> only
|
|
|
|
|
checks features that are within a certain distance of the given position. For large
|
|
|
|
|
icons, the actual geometry of a feature might be too far away and is not considered.</p>
|
|
|
|
|
<p>In this case, set the <code>renderBuffer</code> property of <code>VectorLayer</code> (the default value is 100px):</p>
|
|
|
|
|
<pre><code class="language-javascript">import VectorLayer from <span class="string">'ol/layer/Vector'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> vectorLayer = <span class="keyword">new</span> VectorLayer({
|
|
|
|
|
...
|
|
|
|
|
renderBuffer: <span class="number">200</span>
|
|
|
|
|
});</code></pre>
|
|
|
|
|
<p>The recommended value is the size of the largest symbol, line width or label.</p>
|
|
|
|
|
<h2 id="why-is-zooming-or-clicking-in-the-map-off-inaccurate-">Why is zooming or clicking in the map off/inaccurate?</h2>
|
|
|
|
|
<p>OpenLayers does not update the map when the container element is resized. This can be caused by progressive updates
|
|
|
|
|
to CSS styles or manually resizing the map. When that happens, any interaction will become inaccurate: the map would zoom in and out, and end up not being centered on the pointer. This makes it hard to do certain interactions, e.g. selecting the desired feature.</p>
|
|
|
|
|
<p>There is currently no built-in way to react to element's size changes, as <a href="https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver">Resize Observer API</a> is only implemented in Chrome.</p>
|
|
|
|
|
<p>There is however an easy to use <a href="https://github.com/que-etc/resize-observer-polyfill">polyfill</a>:</p>
|
|
|
|
|
<pre><code class="language-javascript">import Map from <span class="string">'ol/Map'</span>;
|
|
|
|
|
import ResizeObserver from <span class="string">'resize-observer-polyfill'</span>;
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> mapElement = document.querySelector(<span class="string">'#map'</span>)
|
|
|
|
|
<span class="keyword">const</span> map = <span class="keyword">new</span> Map({
|
|
|
|
|
target: mapElement
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
<span class="keyword">const</span> sizeObserver = <span class="keyword">new</span> ResizeObserver(() => {
|
|
|
|
|
map.updateSize()
|
|
|
|
|
})
|
|
|
|
|
sizeObserver.observe(mapElement)
|
|
|
|
|
|
|
|
|
|
<span class="comment">// called when the map is destroyed</span>
|
|
|
|
|
<span class="comment">// sizeObserver.disconnect()</span></code></pre>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<footer>
|
|
|
|
|
Code licensed under the <a href='http://www.tldrlegal.com/license/bsd-2-clause-license-(freebsd)'>2-Clause BSD</a>. All documentation <a href='http://creativecommons.org/licenses/by/3.0/'>CC BY 3.0</a>. Thanks to our <a href='/sponsors.html'>sponsors</a>.
|
|
|
|
|
<br>
|
|
|
|
|
<a href="https://www.netlify.com">
|
|
|
|
|
This site is powered by Netlify.
|
|
|
|
|
</a>
|
|
|
|
|
</footer>
|
|
|
|
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|