繁体   English   中英

Openlayers使用OSM样式贴图和GeoJSON矢量图层进行投影

[英]Openlayers projection with OSM style maps and a GeoJSON vector layer

注意:我知道还有另一个与此类似的问题,但尚未得到解答,我需要知道如何使用GeoJSON和OSM处理混合投影。

我很困惑。 我在Android上使用OSMDroid API进行映射,并希望使用OpenLayers和GeoExt复制它,但我有一个包含GeoJSON节点和动作事件的投影问题。

我的tile集是基于OSM的,并且托管在与此HTML / JS相同的Web服务器上。 请在下面查看。 我意识到我的界限不起作用,我的预测可能完全错误。 我一直在测试不同的组合。

问题是我的地图显示正确并且居中。 然而:

  1. 我的GeoJSON特征节点远离地图。 它们处于不同的投影长/纬度,但我不知道如何将GeoJSON long / lat设置或转换为当前地图投影。

  2. 我的mapCtrl不起作用。 当我点击它时,lonlat是另一个投影(OSM投影坐标),我似乎无法转换它们)

  3. 关于范围/界限如何实际工作的任何提示将不胜感激

有人可以请一点投射建议吗? 叹了口气......我对此并不耐心。

在此输入图像描述

这是我的完整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
    }
  ]
}

好的,这是我处理这个问题的方式:

  1. 我在我的后端使用嵌入式Jetty Web服务器,但无论如何,我创建了一个servlet来响应GeoJSON格式数据。 每个要素位置lon / lat在投影之间转换。 (例如EPSG:4326到EPSG:900913)

  2. lon / lat投影对话利用了GeoTools Java API。 这篇博文特别有用( http://ariasprado.name/2012/08/13/quick-and-dirty-coordinate-transforming-using-geotools.html )请注意,你需要经历一段时间的如果您只想包含转换预测所需的罐子,请尝试反复试验。 GeoTools很大,做了很多,并且有很多罐子。

现在,当GeoExt.data.ProtocolProxy加载我的GeoJSON内容时,它已经在OSM兼容的EPSG:900913中。 我本来希望在GeoExt / OpenLayer中完全处理这个问题,但似乎没有一个简单的方法。 我将承认GeoExt和OpenLayers没有超级好的参考文档可供遵循。

我将包含我的GeoTools代码,但上面的“Arias Prado GIS Ramblings”博客文章比我做得更好。 但是,请注意,您必须对罐子进行试验和错误。 投影编码器是动态加载的,而它们又具有来自其他jar的类依赖关系。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM