[Commits] r1538 - in sandbox/ahocevar/playground/ux/Printing: examples ux/data

commits at geoext.org commits at geoext.org
Wed Dec 2 15:22:23 CET 2009


Author: ahocevar
Date: 2009-12-02 15:22:23 +0100 (Wed, 02 Dec 2009)
New Revision: 1538

Modified:
   sandbox/ahocevar/playground/ux/Printing/examples/Printing.js
   sandbox/ahocevar/playground/ux/Printing/ux/data/PrintProvider.js
Log:
added option to determine pages from features on a vector layer; added apidocs; cleaned up api; modified example to use some hard-coded vector features

Modified: sandbox/ahocevar/playground/ux/Printing/examples/Printing.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/examples/Printing.js	2009-12-02 08:38:48 UTC (rev 1537)
+++ sandbox/ahocevar/playground/ux/Printing/examples/Printing.js	2009-12-02 14:22:23 UTC (rev 1538)
@@ -12,11 +12,18 @@
         styleMap: new OpenLayers.StyleMap({
             strokeColor: "red",
             fillColor: "red",
-            fillOpacity: 0.5,
+            fillOpacity: 0.7,
             strokeWidth: 2,
-            pointRadius: 6
+            pointRadius: 12,
+            externalGraphic: "http://openlayers.org/dev/img/marker-blue.png"
         })
     });
+    var geom = OpenLayers.Geometry.fromWKT, Vec = OpenLayers.Feature.Vector;
+    redline.addFeatures([
+        new Vec(geom("POLYGON(15 47, 16 48, 14 49)")),
+        new Vec(geom("LINESTRING(15 48, 16 47, 17 46)")),
+        new Vec(geom("POINT(16 46)"))
+    ]);
     var mapPanel = new GeoExt.MapPanel({
         renderTo: document.body,
         width: 500,
@@ -28,8 +35,5 @@
         zoom: 5
     });
     mapPanel.map.addLayer(redline);
-    var draw = new OpenLayers.Control.DrawFeature(redline, OpenLayers.Handler.Polygon);
-    mapPanel.map.addControl(draw);
-    draw.activate();
     
 });

Modified: sandbox/ahocevar/playground/ux/Printing/ux/data/PrintProvider.js
===================================================================
--- sandbox/ahocevar/playground/ux/Printing/ux/data/PrintProvider.js	2009-12-02 08:38:48 UTC (rev 1537)
+++ sandbox/ahocevar/playground/ux/Printing/ux/data/PrintProvider.js	2009-12-02 14:22:23 UTC (rev 1538)
@@ -1,20 +1,134 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
 Ext.namespace("GeoExt.ux.data");
 
+/** api: (define)
+ *  module = GeoExt.ux.data
+ *  class = PrintProvider
+ *  base_link = `Ext.util.Observable <http://extjs.com/deploy/dev/docs/?class=Ext.util.Observable>`_
+ */
+
+/** api: constructor
+ *  .. class:: PrintProvider
+ * 
+ *  Provides an interface to a Mapfish print servlet or GeoServer printing extension.
+ */
 GeoExt.ux.data.PrintProvider = Ext.extend(Ext.util.Observable, {
     
+    /** api:config[url]
+     *  ``String`` Base url of the print service. Only required if
+     *  :ref:`GeoExt.ux.data.PrintProvider.capabilities` is not provided. This
+     *  is usually something like ``http://path/to/mapfish/print`` for Mapfish,
+     *  and ``http://path/to/geoserver/pdf`` for GeoServer with the printing
+     *  extension installed. This property is usually used when the print
+     *  service is at the same origin as the application (or accessible via
+     *  proxy), and the request method is set to ``POST`` (see
+     *  :ref:`GeoExt.ux.data.PrintProvider.method`).
+     */
+    
+    /** private:property[url]
+     *  ``String`` Base url of the print service. Will always have a trailing "/".
+     */
     url: null,
     
+    /** api:config[capabilities]
+     *  ``Object`` Capabilities of the print service. Only required if
+     *  :ref:`GeoExt.ux.data.PrintProvider.url` is not provided. This is the
+     *  object returned by the ``info.json`` endpoint of the print service,
+     *  and is usually obtained by including a script tag pointing to
+     *  ``http://path/to/printservice/info.json?var=myvar`` in the head of the
+     *  html document, making the capabilities accessible as ``window.myvar``.
+     *  This property is usually used when accessing a remote print service
+     *  with no proxy available, using the ``GET`` method (see
+     *  :ref:`GeoExt.ux.data.PrintProvider.method`).
+     */
+    
+    /** private:property[capabilities]
+     *  ``Object`` Capabilities as returned from the print service.
+     */
     capabilities: null,
     
-    customData: null,
+    /** api:config[method]
+     *  ``String`` Either ``POST`` or ``GET`` (case-sensitive). Method to use
+     *  when talking to the servlet. If the print service is at the same
+     *  origin as the application (or accessible via proxy), then ``POST``
+     *  is recommended. Use ``GET`` when accessing a remote print service with
+     *  no proxy available, but expect issues with character encoding and URLs
+     *  exceeding the maximum length. Default is ``POST``.
+     */
     
+    /** private:property[method]
+     *  ``String`` Either ``POST`` or ``GET`` (case-sensitive). Method to use
+     *  when talking to the servlet.
+     */
     method: "POST",
+
+    /** api:config[customData]
+     *  ``Object`` Custom data to be sent to the print service. Optional. This
+     *  is e.g. useful for complex layout definitions on the server side that
+     *  require additional parameters.
+     */
     
+    /** private:property[customData]
+     *  ``Object`` Custom data to be sent to the print service.
+     */
+    customData: null,
+    
+    /** api:property[scales]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the scales
+     *  available.
+     *  
+     *  Record fields:
+     *  * name - ``String`` the name of the scale
+     *  * value - ``Float`` the scale denominator
+     */
+    scales: null,
+    
+    /** api:property[dpis]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the dpis
+     *  available.
+     *  
+     *  Record fields:
+     *  * name - ``String`` the name of the dpi
+     *  * value - ``Float`` the dots per inch
+     */
+    dpis: null,
+        
+    /** api:property[layouts]
+     *  ``Ext.data.JsonStore`` read-only. A store representing the layouts
+     *  available.
+     *  
+     *  Records fields:
+     *  * name - ``String`` the name of the layout
+     *  * size - ``Object`` width and height of the map in points
+     *  * rotation - ``Boolean`` indicates if rotation is supported
+     */
+    layouts: null,
+    
+    /** private: method[constructor]
+     *  Private constructor override.
+     */
     constructor: function(config) {
         this.initialConfig = config;
         Ext.apply(this, config);
         
         this.addEvents([
+            /** api: events[loadcapabilities]
+             *  Triggered when the capabilities have finished loading. This
+             *  event will only fire when
+             *  :ref:`GeoExt.ux.data.PrintProvider.capabilities` is not
+             *  configured.
+             *  
+             *  Listener arguments:
+             *  * printProvider - :class:`GeoExt.ux.data.PrintProvider` this
+             *    PrintProvider
+             *  * capabilities - ``Object`` the capabilities
+             */
             "loadcapabilities"
         ]);
         
@@ -32,7 +146,11 @@
         
         this.layouts = new Ext.data.JsonStore({
             root: "layouts",
-            fields: ["name", "map"]
+            fields: [
+                "name",
+                {name: "size", mapping: "map"},
+                {name: "rotation", type: "boolean"}
+            ]
         });
         
         if(config.capabilities) {
@@ -45,6 +163,8 @@
         }
     },
     
+    /** private:method[loadCapabilities]
+     */
     loadCapabilities: function() {
         var url = this.url + "info.json";
         Ext.Ajax.request({
@@ -59,6 +179,8 @@
         });
     },
     
+    /** private:method[loadStores]
+     */
     loadStores: function() {
         this.scales.loadData(this.capabilities);
         this.scales.sort("value", "DESC");
@@ -67,47 +189,101 @@
         this.layouts.loadData(this.capabilities);
     },
     
-    print: function(title, comment, map, layout, dpi, center, scale, rotation) {
+    /** api:method[print]
+     *  :param map: ``GeoExt.MapPanel``|``OpenLayers.Map`` The map to print.
+     *      If not provided, ``GeoExt.MapPanel.guess`` will be used to.
+     *  :param options: ``Object`` Print options.
+     *  
+     *  Print options:
+     *  * layout - ``Ext.data.Record``|``String`` the layout for the page.
+     *    One of the records or the ``name`` of one of the records of the
+     *    :ref:`GeoExt.ux.PrintProvider.layouts` store.
+     *  * dpi - ``Ext.data.Record``|``Float`` the dots per inch for the page.
+     *    One of the records or the ``value`` of one of the records of the
+     *    :ref:`GeoExt.ux.PrintProvider.dpis` store.
+     *  * customData - ``Object`` Additional data that will be sent to the
+     *    print service. Optional.
+     *  * layer - ``OpenLayers.Layer.Vector`` a layer containing one or more
+     *    features created by :ref:`GeoExt.ux.PrintProvider.createFeature`.
+     *    For each feature, a page will be created. The center and the
+     *    rotation of the page will be determined from the feature geometry,
+     *    the scale will be taken from the feature's ``scale`` attribute. A
+     *    page title can be provided in the feature's ``title`` property, and
+     *    a page comment in the feature's ``comment`` property. If the
+     *    ``layer`` option is not provided, the following additional options
+     *    will be used to create a single page PDF:
+     *  * center - ``OpenLayers.LonLat``|``Array`` center of a single-page
+     *    map. If not provided, the center of the map will be used.
+     *  * scale - ``Ext.data.Record``|``Float`` The scale of the page. One of
+     *    the records or the ``value`` of one of the records of the
+     *    :ref:`GeoExt.ux.PrintProvider.scales`. If not provided, the smallest
+     *    scale that fits the map viewport at the current zoom level will be
+     *    used.
+     *  * rotation: ``Float`` The page rotation in degrees, counting clockwise
+     *    from North. Optional.
+     *  * title - ``String`` The page title. Optional.
+     *  * comment - ``String`` A page comment. Optional.
+     * 
+     *  Sends the print command to the print service and opens a new window
+     *  with the resulting PDF.
+     */
+    print: function(map, options) {
+        options = options || {};
+        
         map = map || GeoExt.MapPanel.guess();
         if(map instanceof GeoExt.MapPanel) {
             map = map.map;
         }
-        if(layout instanceof Ext.data.Record) {
-            layout = layout.get("name");
+        
+        var layoutName = options.layout || this.layouts.getAt(0);
+        if(layoutName instanceof Ext.data.Record) {
+            layoutName = layoutName.get("name");
         }
-        layout = layout || this.layouts.getAt(0).get("name");
+        
+        var dpi = options.dpi || this.dpis.getAt(0);
         if(dpi instanceof Ext.data.Record) {
             dpi = dpi.get("value");
         }
-        dpi = dpi || this.dpis.getAt(0).get("value");
-        center = center || map.getCenter();
-        if(center instanceof OpenLayers.LonLat) {
-            center = [center.lon, center.lat]
+        
+        var pages;
+        if(options.layer) {
+            pages = this.createPages(options.layer);
+        } else {
+            var center = options.center  || map.getCenter();
+            if(center instanceof OpenLayers.LonLat) {
+                center = [center.lon, center.lat]
+            }
+            
+            var scale = options.scale || this.getBestScale(map, layoutName);
+            if(scale instanceof Ext.data.Record) {
+                scale = scale.get("value");
+            }
+
+            pages = [{
+                mapTitle: options.title || "",
+                comment: options.comment || "",
+                center: center,
+                scale: scale,
+                rotation: options.rotation
+            }];
         }
-        if(scale instanceof Ext.data.Record) {
-            scale = scale.get("value");
-        }
-        scale = scale || this.getBestScale(map, layout);
 
         var layers = [];
         Ext.each(map.layers, function(layer){
-            var enc = this.encodeLayer(layer);
-            enc && layers.push(enc);
+            if(layer != options.layer) {
+                var enc = this.encodeLayer(layer);
+                enc && layers.push(enc);
+            }
         }, this);
+        
         var payload = Ext.apply({
-            pages: [{
-                center: center,
-                mapTitle: title || "",
-                comment: comment || "",
-                scale: scale,
-                rotation: rotation
-            }],
+            pages: pages,
             dpi: dpi,
             units: map.baseLayer.units,
             srs: map.baseLayer.projection.getCode(),
             layers: layers,
-            layout: layout
-        }, this.customData);
+            layout: layoutName
+        }, Ext.applyIf(options.customData, this.customData));
         if(this.method === "GET") {
             window.open(this.capabilities.printURL + "?spec=" +
                 escape(Ext.encode(payload)));
@@ -122,6 +298,51 @@
         }
     },
     
+    /** api:method[getRotation]
+     *  :param feature: ``OpenLayers.Feature.Vector``
+     *  :return: ``Float``
+     *  
+     *  Gets the rotation of a feature that was originally created with
+     *  :ref:`GeoExt.ux.PrintProvider.createFeature`.
+     */
+    getRotation: function(feature) {
+        var points = feature.geometry.components[0].components;
+        var top = new OpenLayers.Geometry.LineString([points[2], points[3]]);
+        var right = new OpenLayers.Geometry.LineString([points[1], points[2]]);
+        var center = feature.geometry.getBounds().getCenterLonLat();
+        var anglePoint = top.getBounds().getCenterLonLat();
+        var dx = anglePoint.lon - center.lon;
+        var dy = anglePoint.lat - center.lat;
+        return Math.atan2(dx, dy) * 180 / Math.PI;
+    },
+    
+    /** private:method[createPages]
+     *  :param layer: ``OpenLayers.Layer.Vector``
+     *  :return: ``Array``
+     *  
+     *  Creates pages from the features of the provided layer.
+     */
+    createPages: function(layer) {
+        var pages = [];
+        Ext.each(layer.features, function(feature) {
+            var center = feature.geometry.getBounds().getCenterLonLat();
+            pages.push({
+                mapTitle: feature.attributes.title || "",
+                comment: feature.attributes.comment || "",
+                center: [center.lon, center.lat],
+                scale: feature.attributes.scale,
+                rotation: feature.getRotation()
+            })
+        }, this);
+        return pages;
+    },
+    
+    /** private:method[encodeLayer]
+     *  :param layer: ``OpenLayers.Layer``
+     *  :return: ``Object``
+     * 
+     *  Encodes a layer for the print service.
+     */
     encodeLayer: function(layer) {
         var encLayer;
         for(var c in GeoExt.ux.data.PrintProvider.encode) {
@@ -133,16 +354,17 @@
         return (encLayer && encLayer.type) ? encLayer : null;
     },
     
+    /** private:method[getLayoutBounds]
+     *  :param map: ``OpenLayers.Map``
+     *  :param scale: ``Float``
+     *  :param layout: ``Ext.data.Record``
+     *  :return: ``OpenLayers.Bounds``
+     * 
+     *  gets the bounds for a given map, scale and layout
+     */
     getLayoutBounds: function(map, scale, layout) {
-        scale = scale || this.getBestScale(map, layout)
-        layout = layout || this.layouts.getAt(0);
+        var size = layout.get("size");
 
-        var size = layout instanceof Ext.data.Record ?
-            layout.get("map") :
-            layout;
-        if(scale instanceof Ext.data.Record) {
-            scale = scale.get("value");
-        }
         var unitsRatio = OpenLayers.INCHES_PER_UNIT[map.baseLayer.units];
         var w = size.width / 72 / unitsRatio * scale / 2;
         var h = size.height / 72 / unitsRatio * scale / 2;
@@ -151,17 +373,23 @@
             center.lon + w, center.lat + h);
     },
     
-    getBestScale: function(map, layout) {
+    /** api:method[getBestScale]
+     *  :param map: ``OpenLayers.Map``
+     *  :param layoutName: ``String``
+     *  :return: ``Float``
+     *  
+     *  Calculates the best scale for a given map and layout. The best scale
+     *  is considered the smallest one where the print page entirely fits
+     *  the currentmap extent.
+     */
+    getBestScale: function(map, layoutName) {
         if(map instanceof GeoExt.MapPanel) {
             map = map.map;
         }
-        if(typeof layout === "string") {
-            layout = this.layouts.getAt(this.layouts.find("name", layout));
-        }
-        layout = layout || this.layouts.getAt(0);
+        var layout = this.layouts.getAt(this.layouts.find("name", layoutName));
         var extent = map.getExtent();
 
-        var bounds;
+        var bounds, scale;
         this.scales.each(function(rec) {
             scale = rec.get("value");
             bounds = this.getLayoutBounds(map, scale, layout);
@@ -170,10 +398,46 @@
             }
         }, this)
         return scale;
+    },
+    
+    /** api:method[createFeature]
+     *  :param map: ``GeoExt.MapPanel``|``OpenLayers.Map`` the map to create a
+     *      layout feature for.
+     *  :param scale: ``Ext.data.Record``|``Float`` the scale of the print page.
+     *      If not provided, :ref:`GeoExt.ux.PrintProvider.getBestScale` will
+     *      be used.
+     *  :param layout: ``Ext.data.Record``|``String`` the layout of the print
+     *      page.
+     *  :return: ``OpenLayers.Feature.Vector`` A feature to be used for the
+     *      layer that determines the print pages in
+     *      :ref:`GeoExt.ux.PrintProvider.print`. 
+     *
+     *  Creates a vector feature that represents the extent of a print page
+     *  for a given map, scale and layout.
+     */
+    createFeature: function(map, scale, layout) {
+        if(map instanceof GeoExt.MapPanel) {
+            map = map.map;
+        }
+        layout = layout || this.layouts.get(0);
+        if(typeof layout === "string") {
+            layout = this.layouts.getAt(this.layouts.find("name", layout));
+        }
+        scale = scale || this.getBestScale(map, layout.get("name"));
+        if(scale instanceof Ext.data.Record) {
+            scale = this.scales.get("value");
+        }
+        return new OpenLayers.Feature.Vector(
+            this.getLayoutBounds(map, scale, layout).toGeometry(),
+            {scale: scale}
+        );
     }
     
 });
 
+/** private:property[encode]
+ *  Sn object providing encoding functions for different layer types.
+ */
 GeoExt.ux.data.PrintProvider.encode = {
     "WMS": function(layer){
         var enc = Ext.apply(GeoExt.ux.data.PrintProvider.encode["HTTPRequest"](layer), {
@@ -210,21 +474,20 @@
         });
     },
     "HTTPRequest": function(layer) {
-        var a = document.createElement(a);
-        a.href = layer.url instanceof Array ? layer.url[0] : layer.url;
+        var url = layer.url instanceof Array ? layer.url[0] : layer.url;
         return {
-            baseURL: a.href, // reading a.href returns an absolute url
+            baseURL: Ext.DomHelper.overwrite(document.createElement("a"),
+                {tag: "a", href: url}).href,
             opacity: (layer.opacity != null) ? layer.opacity : 1.0,
             singleTile: layer.singleTile,
             customParams: {}
         };
     },
     "Image": function(layer) {
-        var a = document.createElement(a);
-        a.href = layer.getURL(layer.extent);
         return {
             type: 'Image',
-            baseURL: a.href, // // reading a.href returns an absolute url
+            baseURL: Ext.DomHelper.overwrite(document.createElement("a"),
+                {tag: "a", href: layer.getURL(layer.extent)}).href,
             opacity: (layer.opacity != null) ? layer.opacity : 1.0,
             extent: layer.extent.toArray(),
             pixelSize: [layer.size.w, layer.size.h],
@@ -239,7 +502,6 @@
             var featureFormat = new OpenLayers.Format.GeoJSON();
             var styleFormat = new OpenLayers.Format.JSON();
             var nextId = 1;
-            var a = document.createElement("a");
             var styleDict = {};
             var feature, style, dictKey, dictItem;
             for(var i=0, len=features.length; i<len; ++i) {
@@ -255,10 +517,10 @@
                     //new style
                     styleDict[dictKey] = styleName = nextId++;
                     if (style.externalGraphic) {
-                        //Make the URLs absolute
-                        a.href = style.externalGraphic;
-                        encStyles[styleName] = Ext.apply({
-                            externalGraphic: a.href
+                        encStyles[styleName] = Ext.applyIf({
+                            externalGraphic: Ext.DomHelper.overwrite(
+                                document.createElement("a"),
+                                {tag: "a", href: style.externalGraphic}).href
                         }, style);
                     } else {
                         encStyles[styleName] = style;



More information about the Commits mailing list