1 /**
  2  * @fileOverview  
  3  * Copyright (c) 2013 Regione Autonoma della Sardegna
  4  * Published under the GPL license.<br>
  5  * See <a href="https://sardegnageoportale.it/webgis/license.txt">https://sardegnageoportale.it/webgis/license.txt</a>
  6  * for the full text of the license.
  7  * @version 0.1
  8  */
  9 
 10 /**
 11  * @require framework/plugins/ClickableAttribution.js
 12  * @require framework/plugins/InfoMetaPopup.js
 13  */
 14 
 15 /**
 16  * @namespace framework.plugins
 17  */
 18 Ext.namespace("framework.plugins");
 19 
 20 /** 
 21  *  Provides control for link to info application.
 22  *  @name_ InfoAerialPhotos
 23  *  @class Provides control for link to info aerial photo.
 24  *  @constructor
 25  *  @extends <a target="_blank" href="http://gxp.opengeo.org/master/doc/lib/plugins/Tool.html">gxp.plugins.Tool</a>
 26  */
 27 framework.plugins.InfoAerialPhotos = Ext.extend(gxp.plugins.Tool,
 28     /** 
 29      * @lends framework.plugins.InfoAerialPhotos.prototype 
 30      */
 31         {          
 32           /**
 33            * plugin type.
 34            * @public
 35            * @type String
 36            */
 37           ptype: "framework_infoaerialphotos",
 38           /**
 39            * Menu text.
 40            * @public
 41            * @type String
 42            */
 43           menuText: "Seleziona immagini aeree",
 44           /**
 45            * Tooltip text.
 46            * @public
 47            * @type String
 48            */
 49           tooltip: "Selezione immagini aeree",
 50           /**
 51            * Css class for icon.
 52            * @public
 53            * @type String
 54            */
 55           iconCls: "gxp-icon-getfeatureinfo",
 56           /**
 57            * ID Double Map component.
 58            * @public
 59            * @type String
 60            */
 61           idDoubleMapComp: null,
 62           /**
 63            * 
 64            * @public
 65            * @type Object
 66            */
 67           popupWindowDefaults: {
 68             // Eddy
 69             title: 'Feature Info',
 70             width: 360,
 71             height: 200,
 72             anchored: false,
 73             hideonmove: false
 74           },
 75           /**
 76            * 
 77            * @public
 78            * @type Object
 79            */
 80           controlDefaults: {
 81             maxFeatures: 8,
 82             hover: false,
 83             drillDown: false,
 84             infoFormat: "application/vnd.ogc.gml",
 85             queryVisible: true
 86           },
 87           /**
 88            * 
 89            * @public
 90            * @type String
 91            */
 92           filexml: 'tilemapresource.xml',
 93           /** 
 94            * Extent of the tile map
 95            * @public
 96            * @type {OpenLayers.Bounds} 
 97            */
 98           extent: null,
 99           /** 
100            * Origin of the tile map
101            * @public
102            * @type {OpenLayers.LonLat} 
103            */
104           tileOrigin: null,
105           /** 
106            * Max resolution of the zero level
107            * @public
108            * @type {float} 
109            */
110           maxResolution: null,
111           /**
112            * Zooom of the tilemap  
113            * @public
114            * @type {int}  
115            */
116           typeImg: null,
117           /** 
118            * Num levels of the tile map
119            * @public
120            * @type {int} 
121            */
122           numLevels: 0,
123           /** 
124            * Resolutions of the tile map
125            * @public
126            * @type {Array} 
127            */
128           resolutions: null,
129           /** 
130            * Service url TMS of the tile map
131            * @public
132            * @type {String} 
133            */
134           tmsUrl: null,
135           /** 
136            * @private
137            * @type {String} 
138            */
139           strisciata: null,
140           /** 
141            * @private
142            * @type {String} 
143            */
144           foto: null,
145           /** 
146            * Layer WMS that show selected fotogramma 
147            * @public
148            * @type {OpenLayers.Layer.WMS} 
149            */
150           fotoLayer: null,
151           /** 
152            * List aerial photos
153            * @public
154            * @type {JSON} 
155            */
156           mappingVoli: null,
157           /** 
158            * Configured double map with aerial Photos
159            * @public
160            * @type {OpenLayers.Map}
161            */  
162           mapVoli: null,
163           /** 
164            * Number volo
165            * @public
166            * @type {String}
167            */
168           volo: null,
169           /**
170             * Image icon button.
171             * @public
172             * @type String
173             */
174           iconButton: 'theme/app/img/camera16x16.png',
175           /**
176            * @private
177            * @param {Object} config configuration object
178            */
179           constructor: function(config) {
180             framework.plugins.InfoAerialPhotos.superclass.constructor.apply(this, arguments);
181           },
182           /**
183            * Create and append info action
184            * @public
185            * @returns {framework.plugins.InfoAerialPhotos} Object with info control inside
186            */
187           addActions: function() {
188 
189 
190             if (this.getfeatureControl) {
191               this.controlDefaults = Ext.apply(this.controlDefaults, this.getfeatureControl);
192             }
193 
194             this.control = new OpenLayers.Control.WMSGetFeatureInfo(this.controlDefaults);
195 
196             //  FeatureInfoPanel via Popup
197             if (this.popupWindow) {
198               var self = this;
199 
200               //The control will be added to the map in constuctor of GeoExt.Action
201               var popupWindowProps = Ext.apply(this.popupWindowDefaults, this.popupWindow);
202 
203               //Add the control to the popupWindow.
204               popupWindowProps.olControl = this.control;
205 
206               //Apply the featureinfopanel-options to the popupWindow.
207               popupWindowProps.featureInfoPanel = this.popupWindow ? this.popupWindow.featureInfoPanel : null;
208 
209               popupWindowProps.map = this.target.mapPanel.map;
210               
211               popupWindowProps.iconButton = this.iconButton;
212               
213               //se ha dei listeners definiti da fuori vengono appesi dopo per essere prioritari rispetto a quelli interni
214               var popupWindowListeners = popupWindowProps.listeners;
215 
216               popupWindowProps.listeners = {
217                 showAerialPhoto: function(record) {
218                   this.openAerialPhoto(record);
219                   //we add to record a method for self representation in json
220                   var volo = this.mappingVoli[record.data.feature.layer.name];
221                   record.toJSON = function() {
222                     var obj = {
223                       idVolo: this.data.feature.layer.name,
224                       volo: volo,
225                       strisciata: this.data.feature.attributes[volo.strisciata].replace(/ /g, "_"),
226                       foto: this.data.feature.attributes[volo.fotogramma]
227                     };
228                     return JSON.stringify(obj);
229                   }
230                   self.fireEvent('aerialPhotoOpened', record);
231                 },
232                 scope: this
233               }
234               
235               if(popupWindowListeners){
236                   for (var attrname in popupWindowListeners) { 
237                       popupWindowProps.listeners[attrname] = popupWindowListeners[attrname]; 
238                   }
239               }
240 
241 
242               var createPopupWindow = function() {
243                 // Create only once, show only when features found
244                 if (!self.featurePopupWindow) {
245                   self.featurePopupWindow = new framework.widgets.search.FeatureInfoPopup(popupWindowProps);
246                 }
247               };
248 
249               // If enabled already create the window.
250               // if (this.pressed) {
251               createPopupWindow();
252               // }
253 
254               this.handler = function() {
255                 createPopupWindow();
256                 self.featurePopupWindow.hide();
257               };
258 
259 
260             }
261 
262             var actions = [];
263 
264             actions.unshift(new GeoExt.Action({
265               menuText: this.menuText,
266               id: this.idBtn,
267               hidden: this.hiddenBtn,
268               iconCls: this.iconCls,
269               tooltip: this.tooltipText,
270               enableToggle: true,
271               toggleGroup: this.toggleGroup,
272               pressed: this.pressed,
273               control: this.control,
274               map: this.target.mapPanel.map,
275               handler: this.handler
276             }));
277 
278             return framework.plugins.InfoAerialPhotos.superclass.addActions.apply(this, [actions]);
279           },
280           /**
281            * Opens an aerialphoto
282            * @param {Object} photo Photogram to open
283            * @public
284            */
285           openAerialPhoto: function(photo) {
286             if (this.mappingVoli) {
287               if (this.idDoubleMapComp) {
288                 Ext.getCmp(this.idDoubleMapComp).checkToggleColumnButton(true);
289                 this.mapVoli = Ext.getCmp(this.idDoubleMapComp).app2.mapPanel.map;
290               }
291               else
292                 this.mapVoli = this.target.mapPanel.map;
293               this.idVolo = photo.data.feature.layer.name;
294               this.volo = this.mappingVoli[photo.data.feature.layer.name];
295               this.tmsUrl = this.volo.tmsUrl;
296               this.strisciata = photo.data.feature.attributes[this.volo.strisciata].replace(/ /g, "_");
297               this.foto = photo.data.feature.attributes[this.volo.fotogramma];
298               var url = this.tmsUrl + '/' + this.strisciata + '_' + this.foto + '/' + this.filexml;
299 
300               Ext.Ajax.request({
301                 url: url,
302                 success: this.fillTileMap,
303                 failure: this.fillTileMapFailure,
304                 scope: this
305               });
306             }
307           },
308           /**
309            * Opens an aerialphoto but using its json representation
310            * @param {String} json json representation of the photogram
311            * @param {int} scale scale level
312            * @public
313            */
314           openFromJSON: function(json, scale) {
315             if (json) {
316               var record = JSON.parse(json);
317               if (this.mappingVoli) {
318                 if (this.idDoubleMapComp) {
319                   Ext.getCmp(this.idDoubleMapComp).checkToggleColumnButton(true);
320                   this.mapVoli = Ext.getCmp(this.idDoubleMapComp).app2.mapPanel.map;
321                 }
322                 else
323                   this.mapVoli = this.target.mapPanel.map;
324                 this.idVolo = record.idVolo;
325                 this.volo = record.volo;
326                 this.tmsUrl = this.volo.tmsUrl;
327                 this.strisciata = record.strisciata;
328                 this.foto = record.foto;
329                 var url = this.tmsUrl + '/' + this.strisciata + '_' + this.foto + '/' + this.filexml;
330 
331                 Ext.Ajax.request({
332                   url: url,
333                   success: function(data) {
334                     this.fillTileMap(data, scale);
335                   },
336                   failure: this.fillTileMapFailure,
337                   scope: this
338                 });
339               }
340             }
341           },
342           /**
343            * Method: fillTileMap 
344            * 
345            * fill this object tile map with the information of the tile map
346            * 
347            * @param data string of the file xml
348            *
349            */
350           fillTileMap: function(data, scale) {
351 
352             var doc = data.responseXML;
353             if (!doc || !doc.documentElement) {
354               doc = data.responseText;
355             }
356 
357             var xml = new OpenLayers.Format.XML();
358             if (typeof doc == "string") {
359               doc = xml.read(doc);
360             }
361 
362             var boundingBoxNode = doc.getElementsByTagName('BoundingBox');
363             if (boundingBoxNode != null && boundingBoxNode[0] != null) {
364               var boundingBox = boundingBoxNode[0];
365               var minx = boundingBox.getAttribute('miny');
366               var miny = boundingBox.getAttribute('minx');
367               var maxx = boundingBox.getAttribute('maxy');
368               var maxy = boundingBox.getAttribute('maxx');
369               if (minx != null && minx != '' && miny != null && miny != '' && maxx != null && maxx != '' && maxy != null && maxy != '') {
370                 this.extent = new OpenLayers.Bounds(minx, miny, maxx, maxy);
371               }
372             }
373             var tileOriginNode = doc.getElementsByTagName('Origin');
374             if (tileOriginNode != null && tileOriginNode[0] != null) {
375               var origin = tileOriginNode[0];
376               var x = origin.getAttribute('y');
377               var y = origin.getAttribute('x');
378               if (x != null && x != '' && y != null && y != '') {
379                 this.tileOrigin = new OpenLayers.LonLat(x, y);
380               }
381             }
382             var tileFormat = doc.getElementsByTagName('TileFormat');
383             if (tileFormat != null && tileFormat[0] != null) {
384               var tileType = tileFormat[0];
385               this.typeImg = tileType.getAttribute('extension');
386             }
387             var tileSet = doc.getElementsByTagName('TileSet');
388             if (tileSet != null && tileSet.length > 0) {
389               this.numLevels = tileSet.length;
390               this.resolutions = [];
391               for (var i = 0; i < tileSet.length; i++) {
392                 var firstTileSet = tileSet[i];
393                 var order = firstTileSet.getAttribute('order');
394                 if (order != null && order == '0') {
395                   var unitsperpixel = firstTileSet.getAttribute('units-per-pixel');
396                   if (unitsperpixel != null) {
397                     this.maxResolution = unitsperpixel;
398                   }
399                   //break;
400                 }
401                 this.resolutions.push(parseFloat(firstTileSet.getAttribute('units-per-pixel')));
402               }
403               this.resolutions = this.resolutions.reverse();
404             }
405 
406             this.updateFotogrammiLayer();
407             /*if (scale) {
408               this.mapVoli.zoomToScale(scale);
409             }*/
410 
411           },
412           /**
413            * Method: fillTileMapFailure 
414            * on failure load url
415            * 
416            * @param data string of the file xml
417            *
418            */
419           fillTileMapFailure: function(data) {
420             alert('Fotogramma non esistente.');
421           },
422           /**
423            * Method: updateFotogrammiLayer
424            * 
425            * Update Fotogrammi Layer to show selected fotogramma
426            *
427            */
428           updateFotogrammiLayer: function() {
429 
430             var options = {
431               projection: "EPSG:3003",
432               id: "mymap",
433               units: 'm',
434               resolutions: this.resolutions,
435               maxResolution: this.maxResolution,
436               maxExtent: this.extent,
437               restrictedExtent: this.extent,
438               numZoomLevels: this.numLevels,
439               panMethod: "null",
440               zoom: 1
441             };
442 
443             this.mapVoli.setOptions(options);
444 
445 
446             var layerOld = this.fotoLayer;
447             var layerName = this.strisciata + '_' + this.foto;
448             this.fotoLayer = new OpenLayers.Layer.TMS(
449                 this.volo.title,
450                 this.tmsUrl,
451                 {
452                   layername: layerName,
453                   type: this.typeImg,
454                   background: "#000000",
455                   maxExtent: this.extent,
456                   tileOrigin: this.tileOrigin,
457                   candidateBaseLayer: true,
458                   displayInLayerSwitcher: false,
459                   serviceVersion: ''
460                 });
461 
462             new framework.plugins.ClickableAttribution({
463               layer: this.fotoLayer,
464               params: {
465                 idVolo: this.idVolo,
466                 strisciata: this.strisciata,
467                 foto: this.foto
468               },
469               text: Ext.isDefined(this.volo.attribution) ? this.volo.attribution : 'no info provided',
470               listeners: {
471                 click: function(layer, params) {
472                   var volo = this.mappingVoli[params.idVolo];
473                   var popup = new framework.plugins.InfoMetaPopup({
474                     titolo: volo.title,
475                     strisciata: params.strisciata,
476                     fotogramma: params.foto,
477                     copyright: volo.attribution,
478                     metadata: volo.metadata
479                   });
480                   popup.show();
481                 }, scope: this
482               }
483             });
484             this.fotoLayer.setIsBaseLayer(true);
485 
486             this.mapVoli.addLayer(this.fotoLayer);
487 
488             if (layerOld !== null)
489             {
490               layerOld.destroy();
491             }
492 
493             this.mapVoli.setBaseLayer(this.fotoLayer);
494             this.mapVoli.zoomToExtent(this.extent);
495           }
496 
497 
498         });
499 
500     Ext.preg(framework.plugins.InfoAerialPhotos.prototype.ptype, framework.plugins.InfoAerialPhotos);
501