[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