首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >映射组件.getWidth()不是一个函数(GeoExt3、MapFish、OpenLayers 4)

映射组件.getWidth()不是一个函数(GeoExt3、MapFish、OpenLayers 4)
EN

Stack Overflow用户
提问于 2019-06-14 22:52:45
回答 1查看 2.6K关注 0票数 0

我正在努力学习教程这里*。但我在地图组件上发现了一些意想不到的东西。

应用程序/安装的背景信息:

我通过克隆这个存储库来安装GeoExt3:https://github.com/geoext/geoext3

这个应用程序最初是一个通用的应用程序:https://github.com/geoext/geoext3/blob/master/universal-app.md

我的应用程序的mapComponent扩展了GeoExt.component.Map,后者扩展了Ext.Component。getWidth()是一个Ext.Component方法。我想知道我的问题是否与继承有关。下面两个api文档让我困惑了一下,但随后意识到,第一个是没有ext组件的GeoExt,第二个是ext组件。

https://geoext.github.io/geoext3/master/docs/#!/api/GeoExt.component.Map http://geoext.github.io/geoext3/master/docs-w-ext/#!/api/GeoExt.component.Map

应用程序代码https://github.com/qnmai/qnmai.github.io/tree/debugprint

我的层、映射和映射组件以这种方式创建(成功):

代码语言:javascript
复制
var t_coupureaerien_source = new ol.source.VectorTile({
  format: new ol.format.MVT(),
  url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' + 'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
})

var t_coupureaerien_style = new ol.style.Style({
  fill: new ol.style.Fill({color: 'rgba(255, 255, 255, 0.6)'}),
  stroke: new ol.style.Stroke({color: '#319FD3', width: 1})
});

var t_coupureaerien_layer = new ol.layer.VectorTile({
  title: 'Coupure Aerien HTA',
  style: t_coupureaerien_style,
  source: t_coupureaerien_source,
  legendUrl: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' + 'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf',
  name: 'Appareil de coupure aerien'
});

var osm_source = new ol.source.OSM({url: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"});
var osm_basemap = new ol.layer.Tile({
  title: 'OSM basemap',
  source: osm_source,
  //legendUrl: 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',
  name: 'OSM basemap'})

var extentLayer = new ol.layer.Vector({
  source: new ol.source.Vector()
});

var view = new ol.View({
  center: ol.proj.fromLonLat([-149.3, -17.7]),
  zoom: 7
});

var my_map = new ol.Map({
  controls: ol.control.defaults().extend([new ol.control.ScaleLine]),
  target: 'map',
  view: view,
  layers: [
    new ol.layer.Group({title: 'Fond de plans', layers: [osm_basemap], name: 'Fond de plans'}),
    new ol.layer.Group({title: 'Réseau Secosud', layers: [coupureaerien_layer], name: 'Réseau Secosud'}),
    extentLayer
  ],
  //overlays: [overlay],
});

var mapComponent = Ext.define('SIG.view.main.Map', {
  // extend: "Ext.panel.Panel",
  extend: 'GeoExt.component.Map',
  xtype: 'mappanel',
  //region: 'center',
  requires: [
    'SIG.view.main.MapController', 'SIG.view.main.MapModel'
  ],

  controller: 'main-map',
  viewModel: {
    type: 'main-map'
  },
  // html: "Hello, World!!"
  map: my_map
});

console.log(mapComponent);
console.log(mapComponent.getWidth());

但是getWidth()给出了这个错误,尽管它是一个映射组件的方法

代码语言:javascript
复制
Uncaught TypeError: mapComponent.getWidth is not a function

我已经将mapComponent对象打印到控制台,超类显示了以下方法。似乎getWidth不在那里。这是问题的一部分吗?(对不起,json格式.我无法让火狐的toSource工作)。第一个想法是它可能是,但是我的对象再次扩展了GeoExt.map.Component,这反过来扩展了Ext.Component,所以这可能不是打印整个链(?)。

代码语言:javascript
复制
superclass: {…}

​​

"$className": "GeoExt.component.Map"

​​

"$inheritableStatics": Object { _checked: true, check: true, normalizeSymbol: true, … }

​​

"$noClearOnDestroy": Object { events: true, hasListeners: true, managedListeners: true, … }

​​

HasListeners: function HasListeners()

​​

addLayer: function addLayer()

​​

alias: Array [ "widget.gx_map", "widget.gx_component_map" ]

​​

applyPointerRest: function applyPointerRest()

​​

applyPointerRestInterval: function applyPointerRestInterval()

​​

applyState: function applyState()

​​

bindOverOutListeners: function bindOverOutListeners()

​​

bindStateOlEvents: function bindStateOlEvents()

​​

bufferedPointerMove: function emptyFn()

​​

childEls: Object { frameTable: {}, frameTL: {}, frameTC: {}, … }

​​

config: Object { pointerRest: false, pointerRestInterval: 1000, pointerRestPixelTolerance: 3, … }

​​

constructor: function constructor()

​​

defaultConfig: Object { pointerRest: false, pointerRestInterval: 1000, pointerRestPixelTolerance: 3, … }

​​

defaultListenerScope: false

​​

getCenter: function getCenter()

​​

getExtent: function getExtent()

​​

getLayers: function getLayers()

​​

getMap: function makeGetter()

​​

getPointerRest: function makeGetter()

​​

getPointerRestInterval: function makeGetter()

​​

getPointerRestPixelTolerance: function makeGetter()

​​

getState: function getState()

​​

getStore: function getStore()

​​

getView: function getView()

​​

isMouseOverMapEl: null

​​

lastPointerPixel: null

​​

layerStore: null

​​

map: null

​​

mapRendered: false

​​

mixins: Object { isDefinedSymbol: {…} }

​​

onMouseOut: function onMouseOut()

​​

onMouseOver: function onMouseOver()

​​

onResize: function onResize()

​​

pointerRestPixelTolerance: 3

​​

registerPointerRestEvents: function registerPointerRestEvents()

​​

removeLayer: function removeLayer()

​​

requires: Array [ Layers()

, Version()

]

​​

self: function Map()

​​

setCenter: function setCenter()

​​

setExtent: function setExtent()

​​

setMap: function setter()

​​

setPointerRest: function setter()

​​

setPointerRestInterval: function setter()

​​

setPointerRestPixelTolerance: function setter()

​​

setView: function setView()

​​

stateEvents: Array [ "aftermapmove" ]

​​

superclass: Object { self: Component()

, superclass: {…}, defaultConfig: {…}, … }

​​

symbols: Array(15) [ "ol.layer.Base", "ol.Map", "ol.Map#addLayer", … ]

​​

unbindOverOutListeners: function unbindOverOutListeners()

​​

unbufferedPointerMove: function unbufferedPointerMove()

​​

unregisterPointerRestEvents: function unregisterPointerRestEvents()

​​

xtype: "gx_map"

​​

xtypes: Array [ "gx_map", "gx_component_map" ]

​​

xtypesChain: Array(4) [ "component", "box", "gx_map", … ]

​​

xtypesMap: Object { component: true, box: true, gx_map: true, … }

​​

<prototype>: Object { self: Component()

, superclass: {…}, defaultConfig: {…}, … }

因此,使用以下代码调用MapFish模块会给出相同的错误:

代码语言:javascript
复制
Ext.require([
  'GeoExt.component.Map',
  'SIG.view.main.Map']);
/**
  * Once the store is loaded, we can create the button with the
  * following assumptions:
  *
  *     * The button will print the first layout
  *     * The attributes used are the first of the above layout
  *     * We'll request the first dpi value of the suggested ones
  * @param {GeoExt.data.MapfishPrintProvider} provider The print
  *     provider.
  */
 var onPrintProviderReady = function(provider) {
     // this is the assumption: take the first layout and render an
     // appropriate extent on the map
     var capabilities = provider.capabilityRec;
     var layout = capabilities.layouts().getAt(0);
     var attr = layout.attributes().getAt(0);
     var clientInfo = attr.get('clientInfo');
     var render = GeoExt.data.MapfishPrintProvider.renderPrintExtent;
     console.log(mapComponent);
     render(mapComponent, extentLayer, clientInfo);

     mapComponent.getView().on('propertychange', function() {
         extentLayer.getSource().clear();
         render(mapComponent, extentLayer, clientInfo);
     });
     description.add({
         xtype: 'button',
         text: 'Print',
         handler: function() {
             var spec = {
                 layout: layout.get('name'),
                 attributes: {}
             };
             var firstFeature = extentLayer.getSource().getFeatures()[0];
             var bbox = firstFeature.getGeometry().getExtent();
             var util = GeoExt.data.MapfishPrintProvider;
             var mapView = mapComponent.getView();
             var serializedLayers = util.getSerializedLayers(
                 mapComponent,
                 function(layer) {
                     // do not print the extent layer
                     var isExtentLayer = (extentLayer === layer);
                     return !isExtentLayer;
                 }
             );
             serializedLayers = unHttpsLayers(serializedLayers);
             serializedLayers.reverse();
             spec.attributes[attr.get('name')] = {
                 bbox: bbox,
                 dpi: clientInfo.dpiSuggestions[0],
                 layers: serializedLayers,
                 projection: mapView.getProjection().getCode(),
                 rotation: mapView.getRotation()
             };
             Ext.create('Ext.form.Panel', {
                 standardSubmit: true,
                 url: 'https://apps.terrestris.de/print-servlet-3.1.2/' +
                     'print/geoext/buildreport.pdf',
                 method: 'POST',
                 items: [
                     {
                         xtype: 'textfield',
                         name: 'spec',
                         value: Ext.encode(spec)
                     }
                 ]
             }).submit();
         }
     });
 };

 Ext.create('GeoExt.data.MapfishPrintProvider', {
     url: 'https://apps.terrestris.de/print-servlet-3.1.2/' +
             'print/geoext/capabilities.json',
     listeners: {
         ready: onPrintProviderReady
     }
 });

对于那些不熟悉MapFishPrintProvider的人来说。这个问题出现在renderPrintExtent中:

代码语言:javascript
复制
/* Copyright (c) 2015-2017 The Open Source Geospatial Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Provides an interface to a Mapfish or GeoServer print module.
 *
 * @class GeoExt.data.MapfishPrintProvider
 */
Ext.define('GeoExt.data.MapfishPrintProvider', {
    extend: 'Ext.Base',
    mixins: [
        'Ext.mixin.Observable',
        'GeoExt.mixin.SymbolCheck'
    ],
    requires: [
        'GeoExt.data.model.print.Capability',
        'Ext.data.JsonStore'
    ],
    // <debug>
    symbols: [
        'ol.Collection',
        'ol.geom.Polygon.fromExtent',
        'ol.Feature',
        'ol.layer.Layer#getSource',
        'ol.layer.Group',
        'ol.source.Vector.prototype.addFeature',
        'ol.View#calculateExtent'
    ],
    // </debug>

    /**
     * @event ready
     * Fires after the PrintCapability store is loaded.
     *
     * @param {GeoExt.data.MapfishPrintProvider} provider The
     *     GeoExt.data.MapfishPrintProvider itself
     */

    config: {
        capabilities: null,
        url: ''
    },

    inheritableStatics: {
        /**
         * An array of objects specifying a serializer and a connected
         * OpenLayers class. This should not be manipulated by hand, but rather
         * with the method #registerSerializer.
         *
         * @private
         */
        _serializers: [],

        /**
         * Registers the passed serializer class as an appropriate serializer
         * for the passed OpenLayers source class.
         *
         * @param {ol.source.Source} olSourceCls The OpenLayers source class
         *    that the passed serializer can serialize.
         * @param {GeoExt.data.serializer.Base} serializerCls The serializer
         *    that can serialize the passed source.
         */
        registerSerializer: function(olSourceCls, serializerCls) {
            var staticMe = GeoExt.data.MapfishPrintProvider;
            staticMe._serializers.push({
                olSourceCls: olSourceCls,
                serializerCls: serializerCls
            });
        },

        /**
         * Unregisters the passed serializer class from the array of available
         * serializers. This may be useful if you want to register a new
         * serializer that is different from a serializer that we provide.
         *
         * @param {GeoExt.data.serializer.Base} serializerCls The serializer
         *    that can serialize the passed source.
         * @return {Boolean} Whether we could unregister the serializer.
         */
        unregisterSerializer: function(serializerCls) {
            var available = GeoExt.data.MapfishPrintProvider._serializers;
            var index;
            Ext.each(available, function(candidate, idx) {
                if (candidate.serializerCls === serializerCls) {
                    index = idx;
                    return false; // break early
                }
            });
            if (Ext.isDefined(index)) {
                Ext.Array.removeAt(available, index);
                return true;
            }
            return false;
        },

        /**
         * Returns a GeoExt.data.serializer.Base capable of serializing the
         * passed source instance or undefined, if no such serializer was
         * previously registered.
         *
         * @param {ol.source.Source} source The source instance to find a
         *    serializer for.
         * @return {GeoExt.data.serializer.Base} A serializer for the passed
         *    source or `undefined`.
         */
        findSerializerBySource: function(source) {
            var available = GeoExt.data.MapfishPrintProvider._serializers;
            var serializer;

            Ext.each(available, function(candidate) {
                if (source instanceof candidate.olSourceCls) {
                    serializer = candidate.serializerCls;
                    return false; // break early
                }
            });
            if (!serializer) {
                Ext.log.warn('Couldn\'t find a suitable serializer for source.'
                    + ' Did you require() an appropriate serializer class?');
            }
            return serializer;
        },

        /**
         * Will return an array of ol-layers by the given collection. Layers
         * contained in `ol.layer.Group`s get extracted and groups get removed
         * from returning array
         *
         * @param {GeoExt.data.store.Layers|ol.Collection|ol.layer.Base[]} coll
         *     The 'collection' of layers to get as array. If passed as
         *     ol.Collection, all items must be `ol.layer.Base`.
         * @return {Array} The flat layers array.
         */
        getLayerArray: function(coll) {
            var me = this;
            var inputLayers = [];
            var outputLayers = [];

            if (coll instanceof GeoExt.data.store.Layers) {
                coll.each(function(layerRec) {
                    var layer = layerRec.getOlLayer();
                    inputLayers.push(layer);
                });
            } else if (coll instanceof ol.Collection) {
                inputLayers = Ext.clone(coll.getArray());
            } else {
                inputLayers = Ext.clone(coll);
            }

            inputLayers.forEach(function(layer) {
                if (layer instanceof ol.layer.Group) {
                    Ext.each(me.getLayerArray(layer.getLayers()),
                        function(subLayer) {
                            outputLayers.push(subLayer);
                        });
                } else {
                    outputLayers.push(layer);
                }
            });
            return outputLayers;
        },

        /**
         * Will return an array of serialized layers for mapfish print servlet
         * v3.0.
         *
         * @param {GeoExt.component.Map} mapComponent The GeoExt map component
         *     to get the the layers from.
         * @param {Function} [filterFn] A function to filter the layers to be
         *     serialized.
         * @param {ol.layer.Base} filterFn.item The layer to check for
         *     inclusion.
         * @param {Number} filterFn.index The index of the layer in the
         *     flattened list.
         * @param {Array} filterFn.array The complete flattened array of layers.
         * @param {Boolean} filterFn.return Return a truthy value to keep the
         *     layer and serialize it.
         * @param {Object} [filterScope] The scope in which the filtering
         *     function will be executed.
         * @return {Array<Object>} An array of serialized layers.
         * @static
         */
        getSerializedLayers: function(mapComponent, filterFn, filterScope) {
            var layers = mapComponent.getLayers();
            var viewRes = mapComponent.getView().getResolution();
            var serializedLayers = [];
            var inputLayers = this.getLayerArray(layers);

            if (Ext.isDefined(filterFn)) {
                inputLayers = Ext.Array.filter(
                    inputLayers, filterFn, filterScope
                );
            }

            Ext.each(inputLayers, function(layer) {
                var source = layer.getSource();
                var serialized = {};

                var serializer = this.findSerializerBySource(source);
                if (serializer) {
                    serialized = serializer.serialize(layer, source, viewRes);
                    serializedLayers.push(serialized);
                }
            }, this);

            return serializedLayers;
        },

        /**
         * Renders the extent of the printout. Will ensure that the extent is
         * always visible and that the ratio matches the ratio that clientInfo
         * contains.
         *
         * @param {GeoExt.component.Map} mapComponent The map component to
         *     render the print extent to.
         * @param {ol.layer.Vector} extentLayer The vector layer to render the
         *     print extent to.
         * @param {Object} clientInfo Information about the desired print
         *     dimensions.
         * @param {Number} clientInfo.width The target width.
         * @param {Number} clientInfo.height The target height.
         * @return {ol.Feature} The feature representing the print extent.
         */
        renderPrintExtent: function(mapComponent, extentLayer, clientInfo) {
            var mapComponentWidth = mapComponent.getWidth();
            var mapComponentHeight = mapComponent.getHeight();
            var currentMapRatio = mapComponentWidth / mapComponentHeight;
            var scaleFactor = 0.6;
            var desiredPrintRatio = clientInfo.width / clientInfo.height;
            var targetWidth;
            var targetHeight;
            var geomExtent;
            var feat;

            if (desiredPrintRatio >= currentMapRatio) {
                targetWidth = mapComponentWidth * scaleFactor;
                targetHeight = targetWidth / desiredPrintRatio;
            } else {
                targetHeight = mapComponentHeight * scaleFactor;
                targetWidth = targetHeight * desiredPrintRatio;
            }

            geomExtent = mapComponent.getView().calculateExtent([
                targetWidth,
                targetHeight
            ]);
            feat = new ol.Feature(ol.geom.Polygon.fromExtent(geomExtent));
            extentLayer.getSource().addFeature(feat);
            return feat;
        }
    },

    /**
     * The capabiltyRec is an instance of 'GeoExt.data.model.print.Capability'
     * and contans the PrintCapabilities of the Printprovider.
     *
     * @property
     * @readonly
     */
    capabilityRec: null,

    constructor: function(cfg) {
        this.mixins.observable.constructor.call(this, cfg);
        if (!cfg.capabilities && !cfg.url) {
            Ext.Error.raise('Print capabilities or Url required');
        }
        this.initConfig(cfg);
        this.fillCapabilityRec();
    },

    /**
     * Creates the store from object or url.
     *
     * @private
     */
    fillCapabilityRec: function() {
        // enhance checks
        var store;
        var capabilities = this.getCapabilities();
        var url = this.getUrl();
        var fillRecordAndFireEvent = function() {
            this.capabilityRec = store.getAt(0);
            if (!this.capabilityRec) {
                this.fireEvent('error', this);
            } else {
                this.fireEvent('ready', this);
            }
        };
        if (capabilities) { // if capability object is passed
            store = Ext.create('Ext.data.JsonStore', {
                model: 'GeoExt.data.model.print.Capability',
                listeners: {
                    datachanged: fillRecordAndFireEvent,
                    scope: this
                }
            });
            store.loadRawData(capabilities);
        } else if (url) { // if servlet url is passed
            store = Ext.create('Ext.data.Store', {
                autoLoad: true,
                model: 'GeoExt.data.model.print.Capability',
                proxy: {
                    type: 'jsonp',
                    url: url,
                    callbackKey: 'jsonp'
                },
                listeners: {
                    load: fillRecordAndFireEvent,
                    scope: this
                }
            });
        }
    }
});

我的Main.js文件:

代码语言:javascript
复制
 Ext.define('SIG.view.main.Main', {
   extend: 'Ext.container.Viewport',

   requires: [
     'Ext.plugin.Viewport', 'Ext.window.MessageBox', 'SIG.view.main.MainController', 'SIG.view.main.MainModel', 'SIG.view.main.List', 'SIG.view.main.Map', 'SIG.view.main.Print'
   ],
   controller: 'main',
   viewModel: 'main',
   layout: 'border',
   items: [
         mapComponent,
         layerTreePanel
   ]

 })

*顺便提一句,这个应用程序对我不起作用,但有一个错误:“处理请求时出错: java.net.MalformedURLException: unknown : data",但我还是决定尝试使用它。

编辑

我已经更新了代码,以使用映射组件呈现上的侦听器创建MapFishPrintProvider,如下所示。不幸的是,这并没有解决我的问题,错误信息保持不变。

代码语言:javascript
复制
var mapComponent = Ext.define('SIG.view.main.Map', {
  // extend: "Ext.panel.Panel",
  extend: 'GeoExt.component.Map',
  xtype: 'mappanel',
  //region: 'center',
  requires: [
    'SIG.view.main.MapController', 'SIG.view.main.MapModel'
  ],

  controller: 'main-map',
  viewModel: {
    type: 'main-map'
  },
  // html: "Hello, World!!"
  map: my_map,

  // Register the on render here
  listeners: {
    render: function(){
      console.log("Map rendered"); //this prints
      Ext.create('GeoExt.data.MapfishPrintProvider', {
         url: 'https://apps.terrestris.de/print-servlet-3.1.2/' +
               'print/geoext/capabilities.json',
         listeners: {
           ready: onPrintProviderReady
         }
      });
    }
  }
});
EN

回答 1

Stack Overflow用户

发布于 2019-07-04 11:08:49

您是否确保在创建MapfishPrintProvider时创建和呈现映射?因为一旦提供程序获得了功能,它就会触发ready事件,不管映射是创建/呈现的还是未创建的。

在地图上注册on render事件,并在那里创建提供者:

代码语言:javascript
复制
var mapComponent = Ext.define('SIG.view.main.Map', {
  // extend: "Ext.panel.Panel",
  extend: 'GeoExt.component.Map',
  xtype: 'mappanel',
  //region: 'center',
  requires: [
    'SIG.view.main.MapController', 'SIG.view.main.MapModel'
  ],

  controller: 'main-map',
  viewModel: {
    type: 'main-map'
  },
  // html: "Hello, World!!"
  map: my_map,

  // Register the on render here
  listeners: {
    render: function(){
      Ext.create('GeoExt.data.MapfishPrintProvider', {
         url: 'https://apps.terrestris.de/print-servlet-3.1.2/' +
               'print/geoext/capabilities.json',
         listeners: {
           ready: onPrintProviderReady
         }
      });
    }
  }
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56605940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档