NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/Chameleon/trunk/Chameleon/ExtentHistory/ExtentHistory.widget.php

Revision 13 (checked in by jcleary, 17 years ago)

Latest Chameleon code checkout from previous repository

Line 
1 <?php
2 /**
3  * ExtentHistory Widget class
4  *
5  * @project     Chameleon
6  * @revision    $Id: ExtentHistory.widget.php,v 1.3 2005/05/26 14:28:09 jlacroix Exp $
7  * @purpose     Extent History Widget class
8  * @author      Paul Spencer (pspencer@dmsolutions.ca)
9  * @copyright
10  * <b>Copyright (c) 2002, DM Solutions Group Inc.</b>
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  */
29  
30 /*
31  * This widget's purpose is to maintain a history
32  * of extents that the user has visited and allow movement forward and
33  * backward through the hisory if possible.
34  *
35  * Extents are maintained with the projection in case the user changes projection
36  * Moving to an extent in the history is a matter of calling a javascript function
37  *
38  * ExtentHistory_Navigate( szDirection='<previous|next>' )
39  *
40  * Calling this function will cause the page to be submitted and the extents for
41  * the appropriate direction loaded.  The projection may also change.
42  *
43  * The widget has one unique attribute, DIRECTION, which is the direction that the
44  * history will navigate when the widget is clicked.
45  *
46  * Session variables:
47  * gaExtentHistory: array of previous extents
48  * gnExtentHistoryPosition: current position in the extent history
49  */
50
51 class ExtentHistory extends CWCWidget
52 {
53     /**
54      * mbNavigate boolean track whether this widget has changed the extents to avoid
55      * pushing them onto the stack.
56      */
57     var $mbNavigate = false;
58    
59     /**
60      * moButton object the widget's interface is represented by a button
61      */
62     var $moButton = null;
63    
64     /**
65      * mszDirection string the direction to navigate when activated
66      */
67     var $mszDirection = '';
68    
69     /**
70      * initialize the ExtentHistory widget
71      *
72      * Note priority is set to last so that all other widgets have
73      * a chance to change the projection or extents first
74      */
75     function ExtentHistory()
76     {
77         parent::CWCWidget();   
78         $this->moButton = new CWCButton( $this );
79         $this->mnPriority = PRIORITY_LAST;   
80    
81                 // set the description for this widget
82         $this->szWidgetDescription = <<<EOT
83 The ExtentHistory widget is a button widget that can be configured to navigate
84 forwards or backwards through a history of extents that the user has visited.
85 EOT;
86
87         $this->maAttributes['DIRECTION'] = new StringAttribute( 'DIRECTION', true, array( 'forward', 'backward' ) );
88
89         // set the maturity level
90         $this->mnMaturityLevel = MATURITY_BETA;
91     }
92    
93     /**
94      * initialize the default setup of the widget
95      */
96     function InitDefaults()
97     {
98         parent::InitDefaults();
99      
100         if (isset($this->maParams['DIRECTION']))
101         {
102             $this->mszDirection = strtolower( $this->maParams['DIRECTION'] );
103         }
104        
105         $this->moButton->InitDefaults();   
106         $this->moButton->setOnClick( 'ExtentHistory_Navigate', $this->mszDirection );
107        
108     }
109
110     /**
111      * handle the widget's navigation actions if requested by the user
112      * @return boolean always true.
113      */
114     function ParseURL()
115     {
116         if ($this->isVarSet('EXTENTHISTORY_NAVIGATE'))
117         {
118             $szDir = $this->getVar('EXTENTHISTORY_NAVIGATE');
119             //make sure it was this widget that caused the navigation ...
120             if ($szDir == $this->mszDirection)
121             {
122                 if ($szDir == 'backward')
123                 {
124                     $this->previousExtent();
125                 }
126                 elseif($szDir == 'forward')
127                 {
128                     $this->nextExtent();
129                 }
130             }
131         }       
132        
133         return true;
134     }
135    
136     /**
137      * returns an array of HTML inputs type=hidden that are used by this widget
138      *
139      * EXTENTHISTORY_NAVIGATE: set to 'next' or 'previous' to navigate
140      * through the extent history
141      *
142      * @return array an array of strings
143      */
144     function GetHTMLHiddenVariables()
145     {
146         $aReturn = $this->moButton->GetHTMLHiddenVariables();
147
148         $szVar = 'EXTENTHISTORY_NAVIGATE';
149         $aReturn[$szVar] = '<input type="hidden" name="'.$szVar.'" value="">';
150        
151         return $aReturn;
152     }
153    
154     /**
155      * return Button javascript stuff
156      * @return array an array of javascript stuff for the button
157      */
158     function GetJavascriptInitFunctions()
159     {
160         //TODO: set button as inactive if we can't go in
161         //the appropriate direction
162         if ($this->mszDirection == 'backward' &&
163             $_SESSION['gnExtentHistoryPosition'] == 0)
164             $this->moButton->mbEnabled = false;
165         elseif ($this->mszDirection == 'forward' &&
166             count($_SESSION['gaExtentHistory']) == $_SESSION['gnExtentHistoryPosition']+1)
167             $this->moButton->mbEnabled = false;
168         return $this->moButton->GetJavascriptInitFunctions();
169     }
170
171     /**
172      * return Button javascript stuff
173      * @return array an array of javascript stuff for the button
174      */
175     function GetJavascriptVariables()
176     {
177         return $this->moButton->GetJavascriptVariables();
178     }
179
180     /**
181      * return Button javascript stuff
182      * @return array an array of javascript stuff for the button
183      */
184     function GetJavascriptOnLoadFunctions()
185     {
186         return $this->moButton->GetJavascriptOnLoadFunctions();
187     }
188
189     /**
190      * return Button javascript stuff
191      * @return array an array of javascript stuff for the button
192      */
193     function GetJavascriptIncludeFunctions()
194     {
195         return $this->moButton->GetJavascriptIncludeFunctions();
196     }
197
198     /**
199      * returns the javascript function used to access the extent history
200      * It first checks to see if it is necessary to record the current extents.
201      *
202      * Functions returned:
203      *
204      * key: ExtentHistory_Navigate
205      * function: ExtentHistory_Navigate( szDirection )
206      * purpose: called with direction "previous" or "next" to naviagage
207      *          through the extent history.
208      *
209      * @return array an array of javascript functions
210      */
211     function GetJavascriptFunctions()
212     {
213         if (!$this->mbNavigate)
214             $this->pushExtents();
215
216         $aReturn = $this->moButton->GetJavascriptFunctions();
217    
218         $nCurrentPosition = $_SESSION['gnExtentHistoryPosition'];
219         $nCount = count( $_SESSION['gaExtentHistory'] );
220        
221         $szFunction = 'ExtentHistory_Navigate';
222         $aReturn[$szFunction] = <<<EOT
223 function {$szFunction}( szDirection )
224 {
225     if (arguments.length == 2)
226         szDirection = arguments[1];
227    
228     var nCurrentPosition = {$nCurrentPosition};
229     var nCount = {$nCount};
230    
231     if (szDirection == 'backward' && nCurrentPosition == 0)
232     {
233         return;
234     }
235        
236     if (szDirection == 'forward' && nCurrentPosition == nCount - 1)
237     {
238         return;
239     }
240    
241     if (szDirection == 'backward' ||
242         szDirection == 'forward')
243     {
244         {$this->mszHTMLForm}.EXTENTHISTORY_NAVIGATE.value = szDirection;
245         {$this->mszHTMLForm}.submit();
246     }
247 }
248 EOT;
249
250         return $aReturn;
251     }
252
253     /**
254      * draw the widget, returns the button.
255      * @return string the button
256      */
257     function DrawPublish()
258     {
259         return $this->moButton->DrawPublish();
260     }
261    
262    
263     /**
264      * push the current extents onto the session extent stack.  This function
265      * takes care of initializing the stack if necessary.  It also tracks
266      * the current position in the stack and deletes future extents if the
267      * user navigates to new extents after having gone backwards in the history
268      * Finally, it checks to see if the current extents match the last extents
269      * and will only push a new entry on if the extents (and projection)
270      * don't match.
271      */
272     function pushExtents()
273     {
274         //this ensures that pushExtents only gets called once regardless
275         //of how many ExtentHistory widgets there are.
276         if (isset($GLOBALS['ExtentHistoryPushExtentsCalled']))
277         {
278             return;
279         }
280         $GLOBALS['ExtentHistoryPushExtentsCalled'] = true;
281        
282         $oExt = $this->moMapObject->oMap->extent;
283         $szProj = $this->moMapObject->oMap->getProjection();
284        
285         $aEntry = array( $oExt->minx, $oExt->miny, $oExt->maxx, $oExt->maxy, $szProj );
286        
287         //check for session stack of extents and initialize if not set
288         if (!isset($_SESSION['gaExtentHistory']))
289         {
290             $_SESSION['gaExtentHistory'] = array();
291         }
292         //check for session current position and initialize if not set
293         if (!isset($_SESSION['gnExtentHistoryPosition']))
294         {
295             $_SESSION['gnExtentHistoryPosition'] = count( $_SESSION['gaExtentHistory'] ) - 1;
296         }
297         //check to see if current position is valid and reset if it is not
298         if (!isset($_SESSION['gaExtentHistory'][$_SESSION['gnExtentHistoryPosition']]))
299         {
300             $_SESSION['gnExtentHistoryPosition'] = count( $_SESSION['gaExtentHistory'] ) - 1;
301         }
302         //check current extents to see if they DONT match the last extents and push the new
303         //extents on if they DONT match
304         if ($_SESSION['gnExtentHistoryPosition'] == -1)
305         {
306             $_SESSION['gaExtentHistory'][] = $aEntry;
307             $_SESSION['gnExtentHistoryPosition'] = 0;           
308         }
309         else
310         {
311             if (!$this->compareEntries($aEntry,
312                       $_SESSION['gaExtentHistory'][$_SESSION['gnExtentHistoryPosition']]))
313             {
314                 //check to see if there are extents in the 'future' and remove them
315                 if (count($_SESSION['gaExtentHistory']) > $_SESSION['gnExtentHistoryPosition'] + 1)
316                 {
317                     $_SESSION['gaExtentHistory'] = array_slice($_SESSION['gaExtentHistory'], 0,
318                                                                $_SESSION['gnExtentHistoryPosition'] + 1 );
319                 }
320                 $_SESSION['gaExtentHistory'][] = $aEntry;
321                 $_SESSION['gnExtentHistoryPosition'] = count( $_SESSION['gaExtentHistory'] ) - 1;
322             }
323         }
324     }
325    
326     /**
327      * navigate to the previous extent if there is one.
328      */
329     function previousExtent( )
330     {
331         if ($_SESSION['gnExtentHistoryPosition'] > 0)
332         {
333             $_SESSION['gnExtentHistoryPosition'] -= 1;
334             $this->applyExtent();
335         }
336     }
337    
338     /**
339      * navigate to the next available extent if there is one.
340      */
341     function nextExtent()
342     {
343         if ($_SESSION['gnExtentHistoryPosition'] < count( $_SESSION['gaExtentHistory'] ) - 1)
344         {
345             $_SESSION['gnExtentHistoryPosition'] += 1;
346             $this->applyExtent();
347         }
348     }
349    
350     /**
351      * apply the current extents to the map object.  This will change
352      * the projection if necessary.  It will not compare the extents
353      * to see if they are the same
354      */
355     function applyExtent()
356     {
357         if (isset($_SESSION['gaExtentHistory'][$_SESSION['gnExtentHistoryPosition']]))
358         {
359             $aEntry = $_SESSION['gaExtentHistory'][$_SESSION['gnExtentHistoryPosition']];
360             if ($this->moMapObject->oMap->getProjection() != $aEntry[4])
361             {
362                 //change projections (and reset units)
363                 $this->moMapObject->oMap->setProjection( $aEntry[4], true );
364             }
365             $this->moMapObject->oMap->setextent( $aEntry[0], $aEntry[1], $aEntry[2], $aEntry[3] );
366             $this->mbNavigate = true;
367         }
368         else
369         {
370             $nPos = $_SESSION['gnExtentHistoryPosition'];
371             $nCount = count( $_SESSION['gaExtentHistory'] );
372             $_SESSION['gErrorManager']->setError( ERR_WARNING, 'ExtentHistory: attempt to set extents to an invalid position ($nPos), only $nCount available');
373         }
374        
375     }
376    
377     /**
378      * compare two extent entries to see if they are approximately the same
379      *
380      * Extent entries are in the form (minx, miny, maxx, maxy, proj)
381      *
382      * Extents are considered equal if projections match and:
383      *
384      * - width is the same within 0.01%
385      * - height is the same within 0.01%
386      * - x coordinates match within error of width
387      * - y coordinates match within error of height
388      *
389      * @param e1 array the first extent
390      * @param e2 array the second extent
391      * @param tolerance float optional, the percentage difference to use,
392      *        default is 0.001 (0.1%)
393      * @return boolean true if the extents are the same, false if not
394      */
395     function compareEntries( $e1, $e2, $tolerance=0.005 )
396     {
397         //compare projections first
398         if ($e1[4] != $e2[4])
399             return false;
400            
401         //test width
402         $w1 = abs($e1[2] - $e1[0]);
403         $w2 = abs($e2[2] - $e2[0]);
404         $pw = abs($w1 - $w2)/$w2;
405         if ($pw > $tolerance)
406             return false;
407        
408         //test height
409         $h1 = abs($e1[3] - $e1[1]);
410         $h2 = abs($e2[3] - $e2[1]);
411         $ph = abs($h1 - $h2)/$h2;
412         if ($ph > $tolerance)
413             return false;
414            
415         //text minx
416         $d = abs($e1[0] - $e2[0]);
417         if ($d > $w1 * $pw)
418             return false;
419        
420         //text miny
421         $d = abs($e1[1] - $e2[1]);
422         if ($d > $h1 * $ph)
423             return false;
424        
425         //text maxx
426         $d = abs($e1[2] - $e2[2]);
427         if ($d > $w1 * $pw)
428             return false;
429        
430         //text maxy
431         $d = abs($e1[3] - $e2[3]);
432         if ($d > $h1 * $ph)
433             return false;
434        
435         //evertyhing matches (within the tolerance
436         return true;
437     }
438 }
439 ?>
Note: See TracBrowser for help on using the browser.