diff --git a/examples/mapguide-untiled.html b/examples/mapguide-untiled.html new file mode 100644 index 0000000000..0d80284c1b --- /dev/null +++ b/examples/mapguide-untiled.html @@ -0,0 +1,50 @@ + + + + + + + + + + + MapGuide untiled example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

MapGuide untiled example

+

Example of a untiled MapGuide map.

+
+

See the mapguide-untiled.js source to see how this is done.

+
+
mapguide
+
+ +
+ +
+ + + + + + diff --git a/examples/mapguide-untiled.js b/examples/mapguide-untiled.js new file mode 100644 index 0000000000..d8b84060c1 --- /dev/null +++ b/examples/mapguide-untiled.js @@ -0,0 +1,40 @@ +goog.require('ol.Map'); +goog.require('ol.RendererHint'); +goog.require('ol.View2D'); +goog.require('ol.layer.Image'); +goog.require('ol.source.MapGuide'); + +var mdf = 'Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition'; +var agentUrl = + 'http://data.mapguide.com/mapguide/mapagent/mapagent.fcgi?USERNAME=Anonymous'; +var bounds = [ + -87.865114442365922, + 43.665065564837931, + -87.595394059497067, + 43.823852564430069 +]; +var map = new ol.Map({ + layers: [ + new ol.layer.Image({ + source: new ol.source.MapGuide({ + projection: 'EPSG:4326', + url: agentUrl, + useOverlay: false, + metersPerUnit: 111319.4908, //value returned from mapguide + params: { + MAPDEFINITION: mdf, + FORMAT: 'PNG' + }, + ratio: 2, + extent: bounds + }) + }) + ], + renderer: ol.RendererHint.CANVAS, + target: 'map', + view: new ol.View2D({ + center: [-87.7302542509315, 43.744459064634], + projection: 'EPSG:4326', + zoom: 12 + }) +}); diff --git a/old/src/ol/interaction/modifyinteraction.js b/old/src/ol/interaction/modifyinteraction.js index 692c0cd74d..fdef1b88e7 100644 --- a/old/src/ol/interaction/modifyinteraction.js +++ b/old/src/ol/interaction/modifyinteraction.js @@ -252,9 +252,9 @@ ol.interaction.Modify.prototype.removeIndex_ = function(features) { nodesToRemove.push(node); } }); - } - for (i = nodesToRemove.length - 1; i >= 0; --i) { - rBush.remove(nodesToRemove[i]); + for (i = nodesToRemove.length - 1; i >= 0; --i) { + rBush.remove(nodesToRemove[i]); + } } }; @@ -368,12 +368,6 @@ ol.interaction.Modify.prototype.handleDragStart = function(evt) { if (!(goog.getUid(node.feature) in distinctFeatures)) { var feature = node.feature; distinctFeatures[goog.getUid(feature)] = true; - var original = new ol.Feature(feature.getAttributes()); - original.setGeometry(feature.getGeometry().clone()); - original.setId(feature.getId()); - original.setOriginal(feature.getOriginal()); - original.setSymbolizers(feature.getSymbolizers()); - feature.setOriginal(original); } if (renderIntent == ol.FeatureRenderIntent.TEMPORARY) { if (ol.coordinate.equals(segment[0], vertex)) { diff --git a/old/src/ol/parser/ogc/filterparser_v1.js b/old/src/ol/parser/ogc/filterparser_v1.js index 6a5822ee4f..3d3ff44d55 100644 --- a/old/src/ol/parser/ogc/filterparser_v1.js +++ b/old/src/ol/parser/ogc/filterparser_v1.js @@ -648,6 +648,7 @@ ol.parser.ogc.Filter_v1.prototype.setFeatureType = function(featureType) { ol.parser.ogc.Filter_v1.prototype.setSrsName = function(srsName) { this.srsName = srsName; if (goog.isDefAndNotNull(this.gmlParser_)) { - this.gmlParser_.srsName = this.srsName; + this.gmlParser_.applyWriteOptions({}, + /** @type {ol.parser.GMLWriteOptions} */ ({srsName: srsName})); } }; diff --git a/old/src/ol/parser/ogc/gmlparser_v2.js b/old/src/ol/parser/ogc/gmlparser_v2.js index 837b5d844e..37bdd9d191 100644 --- a/old/src/ol/parser/ogc/gmlparser_v2.js +++ b/old/src/ol/parser/ogc/gmlparser_v2.js @@ -54,7 +54,8 @@ ol.parser.ogc.GML_v2 = function(opt_options) { for (var i = 0; i < numCoordinates; ++i) { var coord = coordinates[i]; var part = goog.array.concat(coord); - if (this.axisOrientation.substr(0, 2) !== 'en') { + if (goog.isDef(this.axisOrientation) && + this.axisOrientation.substr(0, 2) !== 'en') { part[0] = coord[1]; part[1] = coord[0]; } diff --git a/old/src/ol/parser/ogc/versionedparser.exports b/old/src/ol/parser/ogc/versionedparser.exports new file mode 100644 index 0000000000..8d3189fde9 --- /dev/null +++ b/old/src/ol/parser/ogc/versionedparser.exports @@ -0,0 +1 @@ +@exportProperty ol.parser.ogc.Versioned.prototype.getParser diff --git a/old/src/ol/parser/ogc/wfsparser.exports b/old/src/ol/parser/ogc/wfsparser.exports new file mode 100644 index 0000000000..14dbb32df3 --- /dev/null +++ b/old/src/ol/parser/ogc/wfsparser.exports @@ -0,0 +1,3 @@ +@exportSymbol ol.parser.ogc.WFS +@exportProperty ol.parser.ogc.WFS_v1.prototype.writeGetFeature +@exportProperty ol.parser.ogc.WFS_v1.prototype.writeTransaction diff --git a/old/src/ol/parser/ogc/wfsparser_v1.js b/old/src/ol/parser/ogc/wfsparser_v1.js index 2fb5f685fa..acc0449c8b 100644 --- a/old/src/ol/parser/ogc/wfsparser_v1.js +++ b/old/src/ol/parser/ogc/wfsparser_v1.js @@ -1,31 +1,22 @@ goog.provide('ol.parser.ogc.WFS_v1'); +goog.require('goog.asserts'); goog.require('goog.dom.xml'); +goog.require('ol.expr.Call'); +goog.require('ol.expr.Identifier'); +goog.require('ol.expr.Literal'); +goog.require('ol.geom.Geometry'); goog.require('ol.parser.XML'); -/** - * @typedef {{featureNS: string, - featurePrefix: string, - featureTypes: Array., - handle: string, - outputFormat: string, - nativeElements: Array.<{ - vendorId: string, - safeToIgnore: boolean, - value: string - }>, - maxFeatures: number}} - */ -ol.parser.WFSWriteOptions; - - /** * @constructor * @extends {ol.parser.XML} + * @param {Object=} opt_options Options which will be set on this object. */ -ol.parser.ogc.WFS_v1 = function() { +ol.parser.ogc.WFS_v1 = function(opt_options) { this.defaultNamespaceURI = 'http://www.opengis.net/wfs'; + // TODO set errorProperty this.readers = {}; this.readers[this.defaultNamespaceURI] = { @@ -36,8 +27,13 @@ ol.parser.ogc.WFS_v1 = function() { }; this.writers = {}; this.writers[this.defaultNamespaceURI] = { + /** + * @param {ol.parser.WFSWriteGetFeatureOptions} options Options. + * @return {{node: Node, + * options: ol.parser.WFSWriteGetFeatureOptions}} Object. + * @this {ol.parser.XML} + */ 'GetFeature': function(options) { - options = /** @type {ol.parser.WFSWriteOptions} */(options); var node = this.createElementNS('wfs:GetFeature'); node.setAttribute('service', 'WFS'); node.setAttribute('version', this.version); @@ -51,6 +47,9 @@ ol.parser.ogc.WFS_v1 = function() { if (goog.isDef(options.maxFeatures)) { node.setAttribute('maxFeatures', options.maxFeatures); } + if (goog.isDef(options.srsName)) { + this.setSrsName(options.srsName); + } } for (var i = 0, ii = options.featureTypes.length; i < ii; i++) { options.featureType = options.featureTypes[i]; @@ -61,29 +60,41 @@ ol.parser.ogc.WFS_v1 = function() { 'xsi:schemaLocation', this.schemaLocation); return {node: node, options: options}; }, + /** + * @param {{inserts: Array., + * updates: Array., + * deletes: Array., + * options: ol.parser.WFSWriteTransactionOptions}} obj Object. + * @return {Element} Node. + * @this {ol.parser.XML} + */ 'Transaction': function(obj) { - obj = obj || {}; - var options = /** {ol.parser.WFSWriteOptions} */(obj.options || {}); + var options = obj.options; + this.setFeatureType(options.featureType); + this.setFeatureNS(options.featureNS); + if (goog.isDef(options.srsName)) { + this.setSrsName(options.srsName); + } var node = this.createElementNS('wfs:Transaction'); node.setAttribute('service', 'WFS'); node.setAttribute('version', this.version); if (goog.isDef(options.handle)) { node.setAttribute('handle', options.handle); } - var i, ii; - var features = obj.features; - if (goog.isDefAndNotNull(features)) { - // TODO implement multi option for geometry types - var name, feature; - for (i = 0, ii = features.length; i < ii; ++i) { - feature = features[i]; - // TODO Update (use feature.getOriginal()) - // TODO Insert and Delete - if (goog.isDef(name)) { - this.writeNode(name, { - feature: feature, - options: options - }, null, node); + var i, ii, features, feature; + var operations = { + 'Insert': obj.inserts, + 'Update': obj.updates, + 'Delete': obj.deletes + }; + for (var name in operations) { + features = operations[name]; + if (!goog.isNull(features)) { + // TODO implement multi option for geometry types + for (i = 0, ii = features.length; i < ii; ++i) { + feature = features[i]; + this.writeNode(name, {feature: feature, options: options}, null, + node); } } } @@ -94,12 +105,135 @@ ol.parser.ogc.WFS_v1 = function() { } return node; }, + /** + * @param {{vendorId: string, safeToIgnore: boolean, value: string}} + * nativeElement Native element. + * @return {Node} Node. + * @this {ol.parser.XML} + */ 'Native': function(nativeElement) { var node = this.createElementNS('wfs:Native'); node.setAttribute('vendorId', nativeElement.vendorId); node.setAttribute('safeToIgnore', nativeElement.safeToIgnore); node.appendChild(this.createTextNode(nativeElement.value)); return node; + }, + /** + * @param {{feature: ol.Feature, + * options: ol.parser.WFSWriteTransactionOptions}} obj Object. + * @return {Element} Node. + * @this {ol.parser.XML} + */ + 'Insert': function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNS('wfs:Insert'); + if (goog.isDef(options) && goog.isDef(options.handle)) { + this.setAttributeNS(node, this.defaultNamespaceURI, 'handle', + options.handle); + } + if (goog.isDef(options.srsName)) { + this.setSrsName(options.srsName); + } + this.writeNode('_typeName', feature, options.featureNS, node); + return node; + }, + /** + * @param {{feature: ol.Feature, + * options: ol.parser.WFSWriteTransactionOptions}} obj Object. + * @return {Element} Node. + * @this {ol.parser.XML} + */ + 'Update': function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNS('wfs:Update'); + this.setAttributeNS(node, this.defaultNamespaceURI, 'typeName', + (goog.isDef(options.featureNS) ? options.featurePrefix + ':' : '') + + options.featureType); + if (goog.isDef(options.handle)) { + this.setAttributeNS(node, this.defaultNamespaceURI, 'handle', + options.handle); + } + + // add in fields + var attributes = feature.getAttributes(); + var attribute; + for (var key in attributes) { + attribute = attributes[key]; + // TODO Only add geometries whose values have changed + if (goog.isDef(attribute)) { + this.writeNode('Property', {name: key, value: attribute}, null, node); + } + } + + // add feature id filter + var fid = feature.getId(); + goog.asserts.assert(goog.isDef(fid)); + this.writeNode('Filter', new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.FID), [new ol.expr.Literal(fid)]), + 'http://www.opengis.net/ogc', node); + + return node; + }, + 'Property': function(obj) { + var node = this.createElementNS('wfs:Property'); + this.writeNode('Name', obj.name, null, node); + if (!goog.isNull(obj.value)) { + this.writeNode('Value', obj.value, null, node); + } + return node; + }, + /** + * @param {string} name Name. + * @return {Element} Node. + * @this {ol.parser.XML} + */ + 'Name': function(name) { + var node = this.createElementNS('wfs:Name'); + node.appendChild(this.createTextNode(name)); + return node; + }, + /** + * @param {string|number|ol.geom.Geometry} obj Object. + * @return {Element} Node. + * @this {ol.parser.XML} + */ + 'Value': function(obj) { + var node; + if (obj instanceof ol.geom.Geometry) { + node = this.createElementNS('wfs:Value'); + node.appendChild( + this.getFilterParser().getGmlParser().writeGeometry(obj)); + } else { + node = this.createElementNS('wfs:Value'); + node.appendChild(this.createTextNode(/** @type {string} */ (obj))); + } + return node; + }, + /** + * @param {{feature: ol.Feature, + * options: ol.parser.WFSWriteTransactionOptions}} obj Object. + * @return {Element} Node. + * @this {ol.parser.XML} + */ + 'Delete': function(obj) { + var feature = obj.feature; + var options = obj.options; + var node = this.createElementNS('wfs:Delete'); + this.setAttributeNS(node, this.defaultNamespaceURI, 'typeName', + (goog.isDef(options.featureNS) ? options.featurePrefix + ':' : '') + + options.featureType); + if (goog.isDef(options.handle)) { + this.setAttributeNS(node, this.defaultNamespaceURI, 'handle', + options.handle); + } + var fid = feature.getId(); + goog.asserts.assert(goog.isDef(fid)); + this.writeNode('Filter', new ol.expr.Call(new ol.expr.Identifier( + ol.expr.functions.FID), [new ol.expr.Literal(fid)]), + 'http://www.opengis.net/ogc', node); + return node; } }; goog.base(this); @@ -204,13 +338,27 @@ ol.parser.ogc.WFS_v1.prototype.read = function(data) { /** - * @param {Array.} features The features to write out. - * @param {ol.parser.WFSWriteOptions} options Write options. + * @param {ol.parser.WFSWriteGetFeatureOptions} options Options. + * @return {string} A serialized WFS GetFeature query. + */ +ol.parser.ogc.WFS_v1.prototype.writeGetFeature = function(options) { + var root = this.writers[this.defaultNamespaceURI]['GetFeature'] + .call(this, options); + return this.serialize(root); +}; + + +/** + * @param {Array.} inserts The features to insert. + * @param {Array.} updates The features to update. + * @param {Array.} deletes The features to delete. + * @param {ol.parser.WFSWriteTransactionOptions} options Write options. * @return {string} A serialized WFS transaction. */ -ol.parser.ogc.WFS_v1.prototype.write = function(features, options) { - var root = this.writeNode('Transaction', {features: features, - options: options}); +ol.parser.ogc.WFS_v1.prototype.writeTransaction = + function(inserts, updates, deletes, options) { + var root = this.writeNode('Transaction', {inserts: inserts, + updates: updates, deletes: deletes, options: options}); this.setAttributeNS( root, 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', this.schemaLocation); diff --git a/old/test/spec/ol/parser/ogc/wfs_v1.test.js b/old/test/spec/ol/parser/ogc/wfs_v1.test.js index 22bf07fc01..69fc103d81 100644 --- a/old/test/spec/ol/parser/ogc/wfs_v1.test.js +++ b/old/test/spec/ol/parser/ogc/wfs_v1.test.js @@ -19,17 +19,15 @@ describe('ol.parser.ogc.WFS', function() { var url = 'spec/ol/parser/ogc/xml/wfs_v1/GetFeature.xml'; afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.WFS_v1_0_0(); - var output = p.writers[p.defaultNamespaceURI]['GetFeature']. - apply(p, [{ - featureNS: 'http://www.openplans.org/topp', - featureTypes: ['states'], - featurePrefix: 'topp', - handle: 'handle_g', - maxFeatures: 1, - outputFormat: 'json' - } - ]); - expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml); + var output = p.writeGetFeature({ + featureNS: 'http://www.openplans.org/topp', + featureTypes: ['states'], + featurePrefix: 'topp', + handle: 'handle_g', + maxFeatures: 1, + outputFormat: 'json' + }); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); done(); }); }); @@ -38,12 +36,44 @@ describe('ol.parser.ogc.WFS', function() { var url = 'spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml'; afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.WFS_v1_0_0(); - var output = p.writers[p.defaultNamespaceURI]['Transaction']. - apply(p, [{ - options: {handle: 'handle_t'} - } - ]); - expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml); + var output = p.writeTransaction(null, null, null, {handle: 'handle_t'}); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); + done(); + }); + }); + + it('handles writing out transactions', function(done) { + var url = 'spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml'; + afterLoadXml(url, function(xml) { + var parser = new ol.parser.ogc.WFS_v1_0_0(); + + var insertFeature = new ol.Feature({ + the_geom: new ol.geom.MultiPoint([[1, 2]]), + foo: 'bar', + nul: null + }); + var inserts = [insertFeature]; + var updateFeature = new ol.Feature({ + the_geom: new ol.geom.MultiPoint([[1, 2]]), + foo: 'bar', + // null value gets Property element with no Value + nul: null, + // undefined value means don't create a Property element + unwritten: undefined + }); + updateFeature.setId('fid.42'); + var updates = [updateFeature]; + + var deleteFeature = new ol.Feature(); + deleteFeature.setId('fid.37'); + var deletes = [deleteFeature]; + + var output = parser.writeTransaction(inserts, updates, deletes, { + featureNS: 'http://www.openplans.org/topp', + featureType: 'states', + featurePrefix: 'topp' + }); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); done(); }); }); @@ -52,7 +82,7 @@ describe('ol.parser.ogc.WFS', function() { var url = 'spec/ol/parser/ogc/xml/wfs_v1/Native.xml'; afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.WFS_v1_1_0(); - var output = p.write(null, {nativeElements: [{ + var output = p.writeTransaction(null, null, null, {nativeElements: [{ vendorId: 'ORACLE', safeToIgnore: true, value: 'ALTER SESSION ENABLE PARALLEL DML' @@ -70,14 +100,12 @@ describe('ol.parser.ogc.WFS', function() { var url = 'spec/ol/parser/ogc/xml/wfs_v1/GetFeatureMultiple.xml'; afterLoadXml(url, function(xml) { var p = new ol.parser.ogc.WFS_v1_0_0(); - var output = p.writers[p.defaultNamespaceURI]['GetFeature']. - apply(p, [{ - featureNS: 'http://www.openplans.org/topp', - featureTypes: ['states', 'cities'], - featurePrefix: 'topp' - } - ]); - expect(goog.dom.xml.loadXml(p.serialize(output))).to.xmleql(xml); + var output = p.writeGetFeature({ + featureNS: 'http://www.openplans.org/topp', + featureTypes: ['states', 'cities'], + featurePrefix: 'topp' + }); + expect(goog.dom.xml.loadXml(output)).to.xmleql(xml); done(); }); }); @@ -87,6 +115,8 @@ describe('ol.parser.ogc.WFS', function() { }); goog.require('goog.dom.xml'); +goog.require('ol.Feature'); +goog.require('ol.geom.MultiPoint'); goog.require('ol.parser.ogc.WFS'); goog.require('ol.parser.ogc.WFS_v1_0_0'); goog.require('ol.parser.ogc.WFS_v1_1_0'); diff --git a/old/test/spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml b/old/test/spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml index b147dc07f4..98527bfc2d 100644 --- a/old/test/spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml +++ b/old/test/spec/ol/parser/ogc/xml/wfs_v1/Transaction.xml @@ -1 +1 @@ - + diff --git a/old/test/spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml b/old/test/spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml new file mode 100644 index 0000000000..22c0886045 --- /dev/null +++ b/old/test/spec/ol/parser/ogc/xml/wfs_v1/TransactionMulti.xml @@ -0,0 +1,45 @@ + + + + + + + + 1,2 + + + + + bar + + + + + the_geom + + + + + 1,2 + + + + + + + foo + bar + + + nul + + + + + + + + + + + \ No newline at end of file diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 1762bbcb63..33aa022d0b 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -440,6 +440,31 @@ * @property {boolean|undefined} visible Visibility. Default is `true` (visible). */ +/** + * @typedef {Object} ol.parser.WFSWriteGetFeatureOptions + * @property {string} featureNS The namespace URI used for features. + * @property {string} featurePrefix The prefix for the feature namespace. + * @property {Array.} featureTypes The feature type names. + * @property {string|undefined} srsName SRS name. For WFS 1.1.0, this is + * required. In WFS 1.0.0, no srsName attribute will be set on geometries + * when this is not provided. + * @property {string|undefined} handle Handle. + * @property {string|undefined} outputFormat Output format. + * @property {number} maxFeatures Maximum number of features to fetch. + */ + +/** + * @typedef {Object} ol.parser.WFSWriteTransactionOptions + * @property {string} featureNS The namespace URI used for features. + * @property {string} featurePrefix The prefix for the feature namespace. + * @property {string} featureType The feature type name. + * @property {string|undefined} srsName SRS name. No srsName attribute will be + * set on geometries when this is not provided. + * @property {string|undefined} handle Handle. + * @property {Array.} nativeElements Native elements. Currently not + * supported. + */ + /** * @typedef {Object} ol.source.BingMapsOptions * @property {string|undefined} culture Culture code. Default is `en-us`. @@ -461,6 +486,22 @@ * @proprtty {string|undefined} url URL. */ +/** + * @typedef {Object} ol.source.MapGuideOptions + * @property {string|undefined} url The mapagent url. + * @property {number|undefined} metersPerUnit The meters-per-unit value. + * @property {ol.Extent|undefined} extent Extent.. + * @property {boolean|undefined} useOverlay If true, will use + * GETDYNAMICMAPOVERLAYIMAGE. + * @property {ol.proj.ProjectionLike} projection Projection. + * @property {number|undefined} ratio Ratio. 1 means image requests are the size + * of the map viewport, 2 means twice the size of the map viewport, and so + * on. + * @property {Array.|undefined} resolutions Resolutions. If specified, + * requests will be made for these resolutions only. + * @property {Object|undefined} params Additional parameters. + */ + /** * @typedef {Object} ol.source.MapQuestOptions * @property {ol.TileLoadFunctionType|undefined} tileLoadFunction Optional diff --git a/src/ol/source/mapguidesource.exports b/src/ol/source/mapguidesource.exports new file mode 100644 index 0000000000..c386f721e0 --- /dev/null +++ b/src/ol/source/mapguidesource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.MapGuide diff --git a/src/ol/source/mapguidesource.js b/src/ol/source/mapguidesource.js new file mode 100644 index 0000000000..974c69b1bc --- /dev/null +++ b/src/ol/source/mapguidesource.js @@ -0,0 +1,138 @@ +goog.provide('ol.source.MapGuide'); + +goog.require('goog.object'); +goog.require('goog.uri.utils'); +goog.require('ol.ImageUrlFunction'); +goog.require('ol.extent'); +goog.require('ol.source.Image'); + + + +/** + * @constructor + * @extends {ol.source.Image} + * @param {ol.source.MapGuideOptions} options Options. + */ +ol.source.MapGuide = function(options) { + + var imageUrlFunction; + if (goog.isDef(options.url)) { + var params = goog.isDef(options.params) ? options.params : {}; + imageUrlFunction = ol.ImageUrlFunction.createFromParamsFunction( + options.url, params, goog.bind(this.getUrl, this)); + } else { + imageUrlFunction = ol.ImageUrlFunction.nullImageUrlFunction; + } + + goog.base(this, { + extent: options.extent, + projection: options.projection, + resolutions: options.resolutions, + imageUrlFunction: imageUrlFunction + }); + + /** + * @private + * @type {number} + */ + this.metersPerUnit_ = goog.isDef(options.metersPerUnit) ? + options.metersPerUnit : 1; + + /** + * @private + * @type {number} + */ + this.ratio_ = goog.isDef(options.ratio) ? options.ratio : 1; + + /** + * @private + * @type {boolean} + */ + this.useOverlay_ = goog.isDef(options.useOverlay) ? + options.useOverlay : false; + + /** + * @private + * @type {ol.Image} + */ + this.image_ = null; + +}; +goog.inherits(ol.source.MapGuide, ol.source.Image); + + +/** + * @inheritDoc + */ +ol.source.MapGuide.prototype.getImage = + function(extent, resolution, projection) { + resolution = this.findNearestResolution(resolution); + + var image = this.image_; + if (!goog.isNull(image) && + image.getResolution() == resolution && + ol.extent.containsExtent(image.getExtent(), extent)) { + return image; + } + + if (this.ratio_ != 1) { + extent = extent.slice(); + ol.extent.scaleFromCenter(extent, this.ratio_); + } + var width = (extent[2] - extent[0]) / resolution; + var height = (extent[3] - extent[1]) / resolution; + var size = [width, height]; + + this.image_ = this.createImage(extent, resolution, size, projection); + return this.image_; +}; + + +/** + * @param {ol.Extent} extent The map extents. + * @param {ol.Size} size the viewport size. + * @return {number} The computed map scale. + */ +ol.source.MapGuide.prototype.getScale = function(extent, size) { + var mcsW = extent[2] - extent[0]; + var mcsH = extent[3] - extent[1]; + var devW = size[0]; + var devH = size[1]; + var dpi = 96; + var mpu = this.metersPerUnit_; + var mpp = 0.0254 / dpi; + if (devH * mcsW > devW * mcsH) { + return mcsW * mpu / (devW * mpp); // width limited + } else { + return mcsH * mpu / (devH * mpp); // height limited + } +}; + + +/** + * @param {string} baseUrl The mapagent url. + * @param {Object.} params Request parameters. + * @param {ol.Extent} extent Extent. + * @param {ol.Size} size Size. + * @param {ol.proj.Projection} projection Projection. + * @return {string} The mapagent map image request URL. + */ +ol.source.MapGuide.prototype.getUrl = + function(baseUrl, params, extent, size, projection) { + var scale = this.getScale(extent, size); + var baseParams = { + 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE', + 'VERSION': '2.0.0', + 'LOCALE': 'en', + 'CLIENTAGENT': 'ol.source.MapGuide source', + 'CLIP': '1', + 'SETDISPLAYDPI': 96, + 'SETDISPLAYWIDTH': Math.round(size[0]), + 'SETDISPLAYHEIGHT': Math.round(size[1]), + 'SETVIEWSCALE': scale, + 'SETVIEWCENTERX': (extent[0] + extent[2]) / 2, + 'SETVIEWCENTERY': (extent[1] + extent[3]) / 2 + }; + goog.object.extend(baseParams, params); + return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); +};