注意:我知道还有另一个与此类似的问题,但尚未得到解答,我需要知道如何使用 GeoJSON 和 OSM 处理混合投影。
我很困惑。我在 Android 上使用 OSMDroid API 进行映射,并想使用 OpenLayers 和 GeoExt 复制它,但我遇到了包含 GeoJSON 节点和 Action 事件的投影问题。
我的图 block 集是基于 OSM 的,并且托管在与此 HTML/JS 相同的 Web 服务器上。请在下面查看所有内容。我意识到我的界限不起作用,我的预测可能完全错误。我一直在测试不同的组合。
问题是我的 map 显示正确并且居中。然而:
我的 GeoJSON 特征节点离 map 很远。它们在不同的投影 long/lat 中,但我不知道如何将 GeoJSON long/lat 设置或转换为当前 map 投影。
我的 mapCtrl 不工作。当我点击它时,lonlat 是另一个投影(OSM 投影坐标),我似乎无法转换它们)
如能提供有关范围/边界实际工作原理的任何提示,我们将不胜感激
有人可以帮忙提供一些投影建议吗?唉......我对此没有足够的耐心。
这是我的完整 JS:
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"
}
);
这是我正在使用的 GeoJSON:
{
"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
}
]
}
最佳答案
好的,这是我处理这个问题的方式:
我在后端使用嵌入式 Jetty Web 服务器,但是 不管怎样,我创建了一个 servlet 来响应 GeoJSON 格式的数据。 每个特征位置经度/纬度在投影之间转换。 (例如 EPSG:4326 到 EPSG:900913)
经度/纬度投影对话利用了 GeoTools Java API。 这篇博文特别有帮助 ( http://ariasprado.name/2012/08/13/quick-and-dirty-coordinate-transforming-using-geotools.html ) 请注意,如果 你只想包括转换你所需的 jar 预测。 GeoTools 很大,功能很多,并且有很多 jar 。
现在,当 GeoExt.data.ProtocolProxy 加载我的 GeoJSON 内容时,它已经在 OSM 兼容的 EPSG:900913 中。我本来想在 GeoExt/OpenLayer 中完全处理这个问题,但似乎没有简单的方法。我承认 GeoExt 和 OpenLayers 没有非常棒的引用文档可供引用。
我会包含我的 GeoTools 代码,但上面的“Arias Prado GIS Ramblings”博客文章比我做得更好。不过,请再次注意,您必须反复试验这些 jar 。投影编码器是动态加载的,它们又具有来自其他 jar 的类依赖性。
关于javascript - 使用 OSM 样式 map 和 GeoJSON 矢量图层的 Openlayers 投影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21690724/