Using Openlayers 3 and proj4js with RequireJS - javascript

I am experiencing an issue when using Openlayers 3 and proj4js with RequireJS.
Using a standard JavaScript file and html, I have working code to display a map and show the coordinates in EPSG:27700 using an Openlayers mouse position control.
When I make use of RequireJS (see the code below), the code fails due to the proj.get returning "undefined". The error in Chrome would suggest that Require is throwing the error.
I have tried to use shims, but this didn't work and I am not convinced that this is the right approach. Can anyone advise me how to get this working?
require.config({
baseUrl: './',
paths: {
'domReady': '../lib/domReady',
'openlayers': '../lib/ol',
'proj4': '../lib/proj4'
}
});
require([
'domReady',
'openlayers',
'proj4'
], function (domReady, openLayers, proj4) {
"use strict";
function getLayers() {
var baseLayer = new openLayers.layer.Tile({
source: new openLayers.source.OSM()
});
return [baseLayer];
};
domReady(function () {
proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs');
openLayers.proj.get("EPSG:27700").setExtent([0, 0, 700000, 1300000]);
var mousePositionControl = new openLayers.control.MousePosition({
coordinateFormat: openLayers.coordinate.createStringXY(4),
projection: 'EPSG:27700'
});
var map = new openLayers.Map({
target: 'map',
layers: getLayers(),
controls: [mousePositionControl],
view: new openLayers.View({
projection: 'EPSG:27700',
center: [300000, 500000],
resolutions: [4500, 3200, 2400, 1600, 800, 400, 200, 100, 50, 25, 10, 5, 2.5, 1, 0.5, 0.25, 0.125, 0.0625],
zoom: 3,
minResolution: 25,
maxResolution: 800
})
});
});
});

You have to tell OpenLayers how to find proj4.js first:
openLayers.proj.setProj4(proj4);
The above snippet requires OpenLayers >= v3.13.0, and assumes a setup like in the code snippet in the question.

Related

OpenLayers 6.8 : How to get Geojson Vector coordinates?

I have a basic map with openlayers 6.8.
I display markers from geojson.
Example of a geojson :
const geoMoscow = new ol.layer.Vector({
source: new ol.source.Vector({
url: './assets/moscow.geojson',
format: new ol.format.GeoJSON()
}),
visible: true,
title: 'geojson',
style: new ol.style.Style({
fill: fillStyle,
stroke: strokeStyle,
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: [245, 49, 5, 1]
}),
radius: 10,
}),
})
})
I want to get this geojson coordinates for further use.
I have been reading many code examples that uses geojson.getSource().getFeatures() that allows to acces the getCoordinates() method from each feature.
Unfortunetly geoMoscow.getSource().getFeatures() gives an empty array.
I am obviously missing something there about openlayers logic.
It seems totally doable because my geojson contains a feature object with the coordinates in it but I am unable to access it.
TLDR : How to access informations like coordinates from this geojson Vector.
You must wait until the source is loaded and parsed
geoMoscow.getSource().on('featuresloadend', function(){
console.log(geoMoscow.getSource().getFeatures());
});
The source will not load until it is added to a map.

How to retrieve data from JSON file without manually entering the data mapbox

I want to use a JSON file containing coordinates to plot points on a map with Mapbox and add markers at those locations. I've followed a few of their tutorials and searched elsewhere (stack overflow, Github etc) to see if I could find a solution but nothing seemed to work. I'm not getting any errors when I open the HTML file in the browser but the markers aren't appearing on the map at the JSON's coordinates and I'm not really sure how to get the JSON's coordinates to be read and then plotted on the map. I want the JSON to be used from the same folder as the project and not a URL so this didn't work for me either.
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoiam1hcHNkamFuZ28iLCJhIjoiY2tydzIwazc4MGNnODJvb2VhNHNhZDd5diJ9.iwGIdgMHrcjbNu1xJRAElQ';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
// style: 'mapbox://styles/mapbox/light-v10',
center: [-0.19346, 51.50405],
zoom: 9
});
map.on('load', () => {
map.addLayer({
id: 'restaurants',
type: 'Point',
source: {
type: 'geojson',
data: './restaurants.json' // replace this with the url of your own geojson
},
paint: {
'circle-radius': [
'interpolate',
['linear'],
['number', ['get', 'coordinates']],
0,
4,
5,
24
],
'circle-color': [
'interpolate',
['linear'],
['number', ['get', 'coordinates']],
0,
1,
2,
3,
4,
5,
],
'circle-opacity': 0.8
}
});
});
I don't know if this is your only error, but this line:
type: 'Point',
should be:
type: 'circle',

Openlayers projection with OSM style maps and a GeoJSON vector layer

Note: I know there's another question similar to this but it hasn't been answered and I need to know how mixed projections can be dealt with with GeoJSON and OSM.
I'm so confused. I was using the OSMDroid API on Android for mapping and wanted to replicate it using OpenLayers and GeoExt, but I've got a projection problem with including GeoJSON nodes and action events.
My tile set is OSM based, and is hosted on the same Web server as this HTML/JS. See it all below. I realize my boundaries aren't working, and my projections might be completely wrong. I've been testing different combinations.
The problem is my map displays correctly and is centered fine. However:
My GeoJSON feature nodes are way off the map. They're in a different projection long/lat, but I don't know how to set or convert GeoJSON long/lat to the current map projection.
My mapCtrl doesn't work. When I click it the lonlat is another projection (the OSM projection coords) and I can't seem to convert them)
Any tips on how extent/bounds actually work would be greatly appreciated
Can someone please help with a bit of projection advice? Sigh... I'm not patient enough for this.
Here's my full JS, as is:
var mapPanel, store, gridPanel, mainPanel, nodePop, mapPop;
Ext.onReady(function() {
var map, mapLayer, vecLayer;
var lon = -70.885610;
var lat = 38.345822;
var zoom = 17;
var maxZoom = 18;
var toProjection = new OpenLayers.Projection("EPSG:4326");
var fromProjection = new OpenLayers.Projection("EPSG:900913");
var extent = new OpenLayers.Bounds(-1.32,51.71,-1.18,51.80).transform(fromProjection, toProjection);
// Setup the node layer feature store and push it all into a vector layer
vecLayer = new OpenLayers.Layer.Vector("vector");
store = new GeoExt.data.FeatureStore({
layer: vecLayer,
fields: [
{name: 'name', type: 'string'},
{name: 'status', type: 'string'}
],
proxy: new GeoExt.data.ProtocolProxy({
protocol: new OpenLayers.Protocol.HTTP({
url: "data/sa.json",
format: new OpenLayers.Format.GeoJSON()
})
}),
autoLoad: true
});
// Setup the basic map layer using OSM style tile retreival to pull tiles
// from the same server hosting this service
map = new OpenLayers.Map(
'map', {
controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.ScaleLine()],
projection: toProjection,
displayProjection: fromProjection,
numZoomLevels: 20,
fractionalZoom: true
});
mapLayer = new OpenLayers.Layer.OSM(
"Local Tiles",
"tiles/${z}/${x}/${y}.png",
{
zoomOffset: 17,
resolutions: [1.194328566741945,0.5971642833709725,0.2985821416854863] // Zoom level 17 - 19
});
map.addLayers([mapLayer, vecLayer]);
// Create a map panel
mapPanel = new GeoExt.MapPanel({
title: "Map",
region: "center",
map: map,
xtype: "gx_mappanel",
center: new OpenLayers.LonLat(lon, lat),
zoom: zoom
});
// Create a grid panel for listing nodes
gridPanel = new Ext.grid.GridPanel({
title: "Nodes",
region: "east",
store: store,
width: 275,
columns: [{
header: "Name",
width: 200,
dataIndex: "name"
}, {
header: "Status",
width: 75,
dataIndex: "status"
}],
sm: new GeoExt.grid.FeatureSelectionModel({
autoPanMapOnSelection: true
})
});
// Create the main view port
new Ext.Viewport({
layout: "border",
items: [{
region: "north",
contentEl: "title",
height: 150
}, mapPanel, gridPanel]
});
var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.setCenter(lonLat, zoom);
// Attach all the event driven stuff here...
// Create a node selection pop up control
function nodeAction(feature) {
nodePop = new GeoExt.Popup({
title: 'Node selected',
location: feature,
width: 200,
html: "",
maximizable: true,
collapsible: true
});
nodePop.on({
close: function() {
if(OpenLayers.Util.indexOf(vectorLayer.selectedFeatures, this.feature) > -1) {
selectCtrl.unselect(this.feature);
}
}
});
nodePop.show();
};
// Attach the pop to node/feature selection events
var selectCtrl = new OpenLayers.Control.SelectFeature(vecLayer);
vecLayer.events.on({
featureselected: function(e) {
nodeAction(e.feature);
}
});
// Create map selection pop up control
function mapAction(lonlat) {
mapPop = new GeoExt.Popup({
title: 'Map selected',
location: lonlat,
width: 200,
html: "You clicked on (" + lonlat.lon.toFixed(2) + ", " + lonlat.lat.toFixed(2) + ")",
maximizable: true,
collapsible: true,
map: mapPanel.map,
anchored: true
});
mapPop.doLayout();
mapPop.show();
};
var mapCtrl = new OpenLayers.Control.Click({
trigger: function(evt) {
var lonlat = mapPanel.map.getLonLatFromViewPortPx(evt.xy);
lonlat.transform(new OpenLayers.Projection("EPSG:4326"), mapPanel.map.getProjectionObject());
//.transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
mapAction(lonlat);
}
});
mapPanel.map.addControl(mapCtrl);
mapCtrl.activate();
});
// A control to handle user clicks on the map
OpenLayers.Control.Click = OpenLayers.Class(
OpenLayers.Control, {
defaultHandlerOptions: {
single: true,
double: false,
pixelTolerance: 0,
stopSingle: true
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
options && options.handlerOptions || {},
this.defaultHandlerOptions
);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Click(
this,
{ click: this.trigger },
this.handlerOptions
);
},
CLASS_NAME: "OpenLayers.Control.Click"
}
);
Here's the GeoJSON I'm using:
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-70.3856,
38.3458
]
},
"type": "Feature",
"properties": {
"name": "Node0",
"status": "Active",
"externalGraphic": "img/node2.png",
"graphicHeight": 75, "graphicWidth": 75
},
"id": 100
},
{
"geometry": {
"type": "Point",
"coordinates": [
-70.885810,
38.344722
]
},
"type": "Feature",
"properties": {
"name": "Node1",
"status": "Active",
"externalGraphic": "img/node2.png",
"graphicHeight": 75, "graphicWidth": 75
},
"id": 101
}
]
}
Ok, here's how I dealt with the issue:
I'm using the embedded the Jetty Web server in my back-end, but
regardless, I created a servlet to respond with GeoJSON format data.
Each Feature location lon/lat is converted between projections.
(e.g. EPSG:4326 to EPSG:900913)
The lon/lat projection conversation leveraged the GeoTools Java API.
This blog post was particularly helpful
(http://ariasprado.name/2012/08/13/quick-and-dirty-coordinate-transforming-using-geotools.html)
Note that you'll need to go through a fair bit of trial and error if
you only want to include the jars required for converting yout
projections. GeoTools is large, does a lot, and has a number of
jars.
Now when the GeoExt.data.ProtocolProxy loads my GeoJSON content it's already in OSM compatible EPSG:900913. I would have liked to deal with this entirely in GeoExt/OpenLayer, but there doesn't appear to be an easy way. I will acknowledge that GeoExt and OpenLayers don't have super great reference documentation to follow.
I'd include my GeoTools code but "Arias Prado GIS Ramblings" blog post above does a better job than I could. Again though, note that you'll have to trial and error the jars. Projection encoders are loaded dynamically, and they in turn have class dependencies from other jars.

Properly Remove LoadMask Once GeoExt MapPanel is Completely Loaded

I would like to have a mask over the whole page which does not get removed until the entire page has completely loaded. More specifically, I have a map created with OpenLayers and GeoExt and I am trying to use an ExtJS loadMask. However, I have not been able to find any other way of doing this other than using a manual setTimeout which I do not want to use. I'd much rather have the mask removed only if the page is completely loaded. I have tried to use the 'loadend' event on the openLayers map as well as windows.onload etc:
My map and loadMask config:
var mask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
mask.show();
Ext.onReady(function() {
var options = {
controls: [new OpenLayers.Control.Navigation()],
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
units: 'm',
allOverlays: false
}
var map = new OpenLayers.Map(options);
map.events.register("loadend", map , function() {
mask.hide(); alert('howdy');
});
var mapPanel = new GeoExt.MapPanel({
title: "Map",
map: map,
id: 'mapPanel',
layerStore: map.layers,
//Set the map to be centered at specified longitude/latitude, transform our layers (SRID=4326) to display properly on Google
//base layers (SRID=900913)
center: new OpenLayers.LonLat(95.20, 30.34).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")),
zoom: 7,
region: "center",
tbar: [measureLength, '-', measureArea, '-'],
bbar: [
{
xtype: "label",
text: "Scale = 1 : "
}
],
items: [{
xtype: "gx_zoomslider",
vertical: true,
height: 300,
aggressive: true,
x: 10,
y: 20,
plugins: new GeoExt.ZoomSliderTip()
}]
});
It seems this event never happens as I never get an alert message. I really really want to get this working, other attempts were:
window.onload = mask.hide();
after the Ext.onReady and at the end of the </body> tag, but then the mask is hidden way before the map is done loading. Could anyone share some insight, I'd really appreciate it!
Add the event 'onMapReady' just after the items like so:
onMapReady: function() {
Ext.getBody().unmask();
}

How to know the Geometry coordinates for google Maps

I found a sample script on Google Code about : Google Maps Javascript API V3 Overlays - http://code.google.com/apis/maps/documentation/javascript/overlays.html#OverlaysOverview
And I want to apply this code to other countries (France, spain...) but I don't know where/how to find the Geometry code like in this script (see commented line)
Here is the code:
var australia = new google.maps.LatLng(-25, 133);
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: australia,
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
layer = new google.maps.FusionTablesLayer({
query: {
select: 'geometry',
from: '815230' // This one
},
styles: [{
polygonOptions: {
fillColor: "#00FF00",
fillOpacity: 0.3
}
}, {
where: "birds > 300",
polygonOptions: {
fillColor: "#0000FF"
}
}, {
where: "population > 5",
polygonOptions: {
fillOpacity: 1.0
}
}]
});
layer.setMap(map);
P.S. I tried to change the google.maps.LatLng(-25, 133) to France Lat&Long but this is used only to center the map on that position.
Thank you for your help
The example you've posted makes use of a FusionTables layer. FusionTables are basically something like a small database or spreadsheet which containt the actual data. The ID that you've commented in the code (815230) is not a coordinate, but the ID of the FusionTable. In fact, you can see the data behind this ID in this link.
You can read more on how to use FusionTables in your maps application in the link that you provided yourself, specifically here. I would recommend reading the article about how to work with FusionTables in general, if you decide to fetch your data from them. You can find a longer article here.

Categories

Resources