Changeset 695801
- Timestamp:
- 04/11/2013 08:31:12 AM (13 years ago)
- Location:
- lazyest-maps
- Files:
-
- 3 added
- 1 deleted
- 8 edited
-
assets/screenshot-1.jpg (added)
-
trunk/css/admin.css (modified) (1 diff)
-
trunk/css/images/maps.png (added)
-
trunk/inc/frontend.php (modified) (1 diff)
-
trunk/inc/settings.php (modified) (8 diffs)
-
trunk/js/gmap3.js (modified) (18 diffs)
-
trunk/js/gmap3.min.js (modified) (1 diff)
-
trunk/js/lazyest-maps.js (modified) (3 diffs)
-
trunk/js/lazyest-maps.min.js (added)
-
trunk/lazyest-maps.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/screenshot-1.jpg (deleted)
Legend:
- Unmodified
- Added
- Removed
-
lazyest-maps/trunk/css/admin.css
r565317 r695801 1 1 #icon-lazyestmaps { 2 background: url('images/maps.png') no-repeat scroll top left transparent;2 background: url('images/maps.png') no-repeat top left; 3 3 } -
lazyest-maps/trunk/inc/frontend.php
r567283 r695801 216 216 217 217 $map .= ' 218 { 219 lat:' . $latitude . ', 220 lng:' . $longitude .', 218 {latLng:[' . $latitude . ', ' . $longitude .'], 221 219 data: ' . $data . ', 222 220 options: { -
lazyest-maps/trunk/inc/settings.php
r566870 r695801 14 14 <div id="lazyest-maps-settings" class="wrap"> 15 15 <?php screen_icon( 'lazyestmaps' ); ?> 16 <h2><?php echo esc_html_e( 'Show your Image Locations on a Map', 'lazyest-maps' ); ?></h2> 17 <div id="poststuff" class="metabox-holder"> 16 <h2><?php echo esc_html_e( 'Show your Image Locations on a Map', 'lazyest-maps' ); ?></h2> 18 17 <form id="lazyest-maps" method="post" action="admin.php"> 19 18 <?php wp_nonce_field( 'lazyest_maps' ); ?> 20 <input type="hidden" name="action" value="lazyest-maps" /> 21 <div id="post-body" class="metabox-holder columns-2"> 22 <?php $this->sidebar() ?> 23 <div id="post-body-content"> 19 <input type="hidden" name="action" value="lazyest-maps" /> 24 20 <fieldset> 25 21 <legend><?php esc_html__( 'Map Settings', 'lazyest-maps' ); ?></legend> 26 22 <?php $this->main_settings(); ?> 27 23 <?php $this->map_settings(); ?> 28 <?php $this->infowindow_settings(); ?> 24 <?php $this->infowindow_settings(); ?> 25 <?php $this->sidebar() ?> 29 26 </fieldset> 30 </div> 31 </div> 32 </form> 33 </div> 27 </form> 34 28 </div> 35 29 … … 42 36 global $lazyest_maps; 43 37 ?> 44 <div class="postbox">45 38 <h3><?php esc_html_e( 'Main Options', 'lazyest-maps' ); ?></h3> 46 <div class="inside">47 39 <table class="form-table"> 48 40 <tbody> … … 67 59 </tbody> 68 60 </table> 69 </div>70 </div>71 61 <?php 72 62 } … … 80 70 global $lazyest_maps; 81 71 ?> 82 <div class="postbox">83 72 <h3><?php esc_html_e( 'Map Options', 'lazyest-maps' ); ?></h3> 84 <div class="inside">85 73 <table class="form-table"> 86 74 <tbody> … … 96 84 </tbody> 97 85 </table> 98 </div>99 </div>100 86 <?php 101 87 } … … 109 95 global $lazyest_maps; 110 96 ?> 111 <div class="postbox">112 97 <h3><?php esc_html_e( 'Info Window Options', 'lazyest-maps' ); ?></h3> 113 <div class="inside">114 98 <table class="form-table"> 115 99 <tbody> … … 134 118 </tbody> 135 119 </table> 136 </div>137 </div>138 120 <?php 139 121 } … … 145 127 */ 146 128 function sidebar() { 147 global $wp_version;148 129 ?> 149 <div id="postbox-container-1" class="postbox-container"> 150 <div id="side-sortables" class="meta-box-sortables"> 151 <?php $this->settings->aboutbox(); ?> 152 <?php $this->submitbox(); ?> 153 </div> 154 </div> 130 <p class="submit"> 131 <input class="button-primary" type="submit" name="lazyest-maps[update]" value="<?php esc_html_e( 'Save Changes', 'lazyest-maps' ) ?>" /> 132 <p><a id="back_link" href="admin.php?page=lazyest-gallery" title="<?php esc_html_e( 'Back to Lazyest Gallery Settings', 'lazyest-maps' ) ?>"><?php esc_html_e( 'Back to Lazyest Gallery Settings', 'lazyest-maps' ) ?></a></p> </p> 155 133 <?php 156 134 } 157 135 158 function submitbox() {159 global $lazyest_maps;160 ?>161 <div id="submitdiv" class="postbox">162 <h3 class="hndle"><span><?php esc_html_e( 'Lazyest Maps', 'lazyest-maps' ) ?></span></h3>163 <div id="version" class="misc-pub-section">164 <div class="versions">165 <p><span id="ls-version-message"><strong><?php echo esc_html_e( 'Version', 'lazyest-maps' ); ?></strong> <?php echo $lazyest_maps->version(); ?></span></p>166 </div>167 </div>168 <div class="misc-pub-section misc-pub-section-last">169 <p><a id="back_link" href="admin.php?page=lazyest-gallery" title="<?php esc_html_e( 'Back to Lazyest Gallery Settings', 'lazyest-maps' ) ?>"><?php esc_html_e( 'Back to Lazyest Gallery Settings', 'lazyest-maps' ) ?></a></p>170 </div>171 <div id="major-publishing-actions">172 <div id="publishing-action">173 <input class="button-primary" type="submit" name="lazyest-maps[update]" value="<?php esc_html_e( 'Save Changes', 'lazyest-maps' ) ?>" />174 </div>175 <div class="clear"></div>176 </div>177 </div>178 <?php179 }180 181 136 } // LazyestMapSettings -
lazyest-maps/trunk/js/gmap3.js
r564181 r695801 1 /* 1 /*! 2 2 * GMAP3 Plugin for JQuery 3 * Version : 4.14 * Date : 201 1-11-183 * Version : 5.0b 4 * Date : 2012-11-17 5 5 * Licence : GPL v3 : http://www.gnu.org/licenses/gpl.html 6 6 * Author : DEMONTE Jean-Baptiste … … 8 8 * Web site : http://gmap3.net 9 9 * 10 * Copyright (c) 2010-201 1Jean-Baptiste DEMONTE10 * Copyright (c) 2010-2012 Jean-Baptiste DEMONTE 11 11 * All rights reserved. 12 12 * … … 36 36 * POSSIBILITY OF SUCH DAMAGE. 37 37 */ 38 39 (function ($) { 40 38 ;(function ($, undef) { 39 40 /***************************************************************************/ 41 /* GMAP3 DEFAULTS */ 42 /***************************************************************************/ 43 // defaults are defined later in the code to pass the rails asset pipeline and 44 //jasmine while google library is not loaded 45 var defaults, gId = 0; 46 47 function initDefaults() { 48 if (!defaults) { 49 defaults = { 50 verbose: false, 51 queryLimit: { 52 attempt: 5, 53 delay: 250, // setTimeout(..., delay + random); 54 random: 250 55 }, 56 classes: { 57 Map : google.maps.Map, 58 Marker : google.maps.Marker, 59 InfoWindow : google.maps.InfoWindow, 60 Circle : google.maps.Circle, 61 Rectangle : google.maps.Rectangle, 62 OverlayView : google.maps.OverlayView, 63 StreetViewPanorama: google.maps.StreetViewPanorama, 64 KmlLayer : google.maps.KmlLayer, 65 TrafficLayer : google.maps.TrafficLayer, 66 BicyclingLayer : google.maps.BicyclingLayer, 67 GroundOverlay : google.maps.GroundOverlay, 68 StyledMapType : google.maps.StyledMapType, 69 ImageMapType : google.maps.ImageMapType 70 }, 71 map: { 72 mapTypeId : google.maps.MapTypeId.ROADMAP, 73 center: [46.578498, 2.457275], 74 zoom: 2 75 }, 76 overlay: { 77 pane: "floatPane", 78 content: "", 79 offset: { 80 x: 0, 81 y: 0 82 } 83 }, 84 geoloc: { 85 getCurrentPosition: { 86 maximumAge: 60000, 87 timeout: 5000 88 } 89 } 90 } 91 } 92 } 93 94 function globalId(id, simulate){ 95 return id !== undef ? id : "gmap3_" + (simulate ? gId + 1 : ++gId); 96 } 97 98 /** 99 * attach events from a container to a sender 100 * todo[ 101 * events => { eventName => function, } 102 * onces => { eventName => function, } 103 * data => mixed data 104 * ] 105 **/ 106 function attachEvents($container, args, sender, id, senders){ 107 if (args.todo.events || args.todo.onces){ 108 var context = { 109 id: id, 110 data: args.todo.data, 111 tag: args.todo.tag 112 }; 113 } 114 if (args.todo.events){ 115 $.each(args.todo.events, function(name, f){ 116 google.maps.event.addListener(sender, name, function(event) { 117 f.apply($container, [senders ? senders : sender, event, context]); 118 }); 119 }); 120 } 121 if (args.todo.onces){ 122 $.each(args.todo.onces, function(name, f){ 123 google.maps.event.addListenerOnce(sender, name, function(event) { 124 f.apply($container, [senders ? senders : sender, event, context]); 125 }); 126 }); 127 } 128 } 129 41 130 /***************************************************************************/ 42 131 /* STACK */ 43 132 /***************************************************************************/ 133 44 134 function Stack (){ 45 135 var st = []; 46 136 this.empty = function (){ 47 for(var i = 0; i < st.length; i++){ 48 if (st[i]){ 49 return false 50 } 51 } 52 return true; 53 } 137 return !st.length; 138 }; 54 139 this.add = function(v){ 55 140 st.push(v); 56 } 57 this.addNext = function ( v){ 58 var t=[], i, k = 0; 59 for(i = 0; i < st.length; i++){ 60 if (!st[i]){ 141 }; 142 this.get = function (){ 143 return st.length ? st[0] : false; 144 }; 145 this.ack = function (){ 146 st.shift(); 147 }; 148 } 149 150 /***************************************************************************/ 151 /* TASK */ 152 /***************************************************************************/ 153 154 function Task(ctx, onEnd, todo){ 155 var session = {}, 156 that = this, 157 current, 158 resolve = { 159 latLng:{ // function => bool (=> address = latLng) 160 map:false, 161 marker:false, 162 infowindow:false, 163 circle:false, 164 overlay: false, 165 getlatlng: false, 166 getmaxzoom: false, 167 getelevation: false, 168 streetviewpanorama: false, 169 getaddress: true 170 }, 171 geoloc:{ 172 getgeoloc: true 173 } 174 }; 175 176 if (typeof todo === "string"){ 177 todo = unify(todo); 178 } 179 180 function unify(todo){ 181 var result = {}; 182 result[todo] = {}; 183 return result; 184 } 185 186 function next(){ 187 var k; 188 for(k in todo){ 189 if (k in session){ // already run 61 190 continue; 62 191 } 63 if (k == 1) { 64 t.push(v); 65 } 66 t.push(st[i]); 67 k++; 68 } 69 if (k < 2) { 70 t.push(v); 71 } 72 st = t; 73 } 74 this.get = function (){ 75 for(var i = 0; i < st.length; i++){ 76 if (st[i]) { 77 return st[i]; 78 } 79 } 80 return false; 81 } 82 this.ack = function (){ 83 for(var i = 0; i < st.length; i++){ 84 if (st[i]) { 85 delete st[i]; 192 return k; 193 } 194 } 195 196 this.run = function (){ 197 var k, opts; 198 while(k = next()){ 199 if (typeof ctx[k] === "function"){ 200 current = k; 201 opts = $.extend(true, {}, defaults[k] || {}, todo[k].options || {}); 202 if (k in resolve.latLng){ 203 if (todo[k].values){ 204 resolveAllLatLng(todo[k].values, ctx, ctx[k], {todo:todo[k], opts:opts, session:session}); 205 } else { 206 resolveLatLng(ctx, ctx[k], resolve.latLng[k], {todo:todo[k], opts:opts, session:session}); 207 } 208 } else if (k in resolve.geoloc){ 209 geoloc(ctx, ctx[k], {todo:todo[k], opts:opts, session:session}); 210 } else { 211 ctx[k].apply(ctx, [{todo:todo[k], opts:opts, session:session}]); 212 } 213 return; // wait until ack 214 } else { 215 session[k] = null; 216 } 217 } 218 onEnd.apply(ctx, [todo, session]); 219 }; 220 221 this.ack = function(result){ 222 session[current] = result; 223 that.run.apply(that, []); 224 }; 225 } 226 227 function getKeys(obj){ 228 var k, keys = []; 229 for(k in obj){ 230 keys.push(k); 231 } 232 return keys; 233 } 234 235 function tuple(args, value){ 236 var todo = {}; 237 238 // "copy" the common data 239 if (args.todo){ 240 for(var k in args.todo){ 241 if ((k !== "options") && (k !== "values")){ 242 todo[k] = args.todo[k]; 243 } 244 } 245 } 246 // "copy" some specific keys from value first else args.todo 247 var i, keys = ["data", "tag", "id", "events", "onces"]; 248 for(i=0; i<keys.length; i++){ 249 copyKey(todo, keys[i], value, args.todo); 250 } 251 252 // create an extended options 253 todo.options = $.extend({}, args.todo.options || {}, value.options || {}); 254 255 return todo; 256 } 257 258 /** 259 * copy a key content 260 **/ 261 function copyKey(target, key){ 262 for(var i=2; i<arguments.length; i++){ 263 if (key in arguments[i]){ 264 target[key] = arguments[i][key]; 265 return; 266 } 267 } 268 } 269 270 /***************************************************************************/ 271 /* GEOCODERCACHE */ 272 /***************************************************************************/ 273 274 function GeocoderCache(){ 275 var cache = []; 276 277 this.get = function(request){ 278 if (cache.length){ 279 var i, j, k, item, eq, 280 keys = getKeys(request); 281 for(i=0; i<cache.length; i++){ 282 item = cache[i]; 283 eq = keys.length == item.keys.length; 284 for(j=0; (j<keys.length) && eq; j++){ 285 k = keys[j]; 286 eq = k in item.request; 287 if (eq){ 288 if ((typeof request[k] === "object") && ("equals" in request[k]) && (typeof request[k] === "function")){ 289 eq = request[k].equals(item.request[k]); 290 } else{ 291 eq = request[k] === item.request[k]; 292 } 293 } 294 } 295 if (eq){ 296 return item.results; 297 } 298 } 299 } 300 }; 301 302 this.store = function(request, results){ 303 cache.push({request:request, keys:getKeys(request), results:results}); 304 }; 305 } 306 307 /***************************************************************************/ 308 /* OVERLAYVIEW */ 309 /***************************************************************************/ 310 function OverlayView(map, opts, latLng, $div) { 311 var that = this, listeners = []; 312 313 defaults.classes.OverlayView.call(this); 314 this.setMap(map); 315 316 this.onAdd = function() { 317 var panes = this.getPanes(); 318 if (opts.pane in panes) { 319 $(panes[opts.pane]).append($div); 320 } 321 $.each("dblclick click mouseover mousemove mouseout mouseup mousedown".split(" "), function(i, name){ 322 listeners.push( 323 google.maps.event.addDomListener($div[0], name, function(e) { 324 $.Event(e).stopPropagation(); 325 google.maps.event.trigger(that, name, [e]); 326 }) 327 ); 328 }); 329 listeners.push( 330 google.maps.event.addDomListener($div[0], "contextmenu", function(e) { 331 $.Event(e).stopPropagation(); 332 google.maps.event.trigger(that, "rightclick", [e]); 333 }) 334 ); 335 this.draw(); 336 }; 337 this.getPosition = function(){ 338 return latLng; 339 }; 340 this.draw = function() { 341 this.draw = function() { 342 var ps = this.getProjection().fromLatLngToDivPixel(latLng); 343 $div 344 .css("left", (ps.x+opts.offset.x) + "px") 345 .css("top" , (ps.y+opts.offset.y) + "px"); 346 } 347 }; 348 this.onRemove = function() { 349 for (var i = 0; i < listeners.length; i++) { 350 google.maps.event.removeListener(listeners[i]); 351 } 352 $div.remove(); 353 }; 354 this.hide = function() { 355 $div.hide(); 356 }; 357 this.show = function() { 358 $div.show(); 359 }; 360 this.toggle = function() { 361 if ($div) { 362 if ($div.is(":visible")){ 363 this.show(); 364 } else { 365 this.hide(); 366 } 367 } 368 }; 369 this.toggleDOM = function() { 370 if (this.getMap()) { 371 this.setMap(null); 372 } else { 373 this.setMap(map); 374 } 375 }; 376 this.getDOMElement = function() { 377 return $div[0]; 378 }; 379 } 380 381 /***************************************************************************/ 382 /* CLUSTERING */ 383 /***************************************************************************/ 384 385 /** 386 * Usefull to get a projection 387 * => done in a function, to let dead-code analyser works without google library loaded 388 **/ 389 function newEmptyOverlay(map){ 390 function Overlay(){ 391 this.onAdd = function(){}; 392 this.onRemove = function(){}; 393 this.draw = function(){}; 394 return defaults.classes.OverlayView.apply(this, []); 395 } 396 Overlay.prototype = defaults.classes.OverlayView.prototype; 397 var obj = new Overlay(); 398 obj.setMap(map); 399 return obj; 400 } 401 402 /** 403 * Class InternalClusterer 404 * This class manage clusters thanks to "todo" objects 405 * 406 * Note: 407 * Individuals marker are created on the fly thanks to the todo objects, they are 408 * first set to null to keep the indexes synchronised with the todo list 409 * This is the "display" function, set by the gmap3 object, which uses theses data 410 * to create markers when clusters are not required 411 * To remove a marker, the objects are deleted and set not null in arrays 412 * markers[key] 413 * = null : marker exist but has not been displayed yet 414 * = false : marker has been removed 415 **/ 416 function InternalClusterer($container, map, radius, maxZoom){ 417 var updating = false, 418 updated = false, 419 redrawing = false, 420 ready = false, 421 enabled = true, 422 that = this, 423 events = [], 424 store = {}, // combin of index (id1-id2-...) => object 425 ids = {}, // unique id => index 426 markers = [], // index => marker 427 todos = [], // index => todo or null if removed 428 values = [], // index => value 429 overlay = newEmptyOverlay(map), 430 timer, projection, 431 ffilter, fdisplay, ferror; // callback function 432 433 main(); 434 435 /** 436 * return a marker by its id, null if not yet displayed and false if no exist or removed 437 **/ 438 this.getById = function(id){ 439 return id in ids ? markers[ids[id]] : false; 440 }; 441 442 /** 443 * remove a marker by its id 444 **/ 445 this.clearById = function(id){ 446 if (id in ids){ 447 var index = ids[id]; 448 449 if (markers[index]){ // can be null 450 markers[index].setMap(null); 451 } 452 delete markers[index]; 453 markers[index] = false; 454 455 delete todos[index]; 456 todos[index] = false; 457 458 delete values[index]; 459 values[index] = false; 460 461 delete ids[id]; 462 updated = true; 463 } 464 }; 465 466 // add a "marker todo" to the cluster 467 this.add = function(todo, value){ 468 todo.id = globalId(todo.id); 469 this.clearById(todo.id); 470 ids[todo.id] = markers.length; 471 markers.push(null); // null = marker not yet created / displayed 472 todos.push(todo); 473 values.push(value); 474 updated = true; 475 }; 476 477 // add a real marker to the cluster 478 this.addMarker = function(marker, todo){ 479 todo = todo || {}; 480 todo.id = globalId(todo.id); 481 this.clearById(todo.id); 482 if (!todo.options){ 483 todo.options = {}; 484 } 485 todo.options.position = marker.getPosition(); 486 attachEvents($container, {todo:todo}, marker, todo.id); 487 ids[todo.id] = markers.length; 488 markers.push(marker); 489 todos.push(todo); 490 values.push(todo.data || {}); 491 updated = true; 492 }; 493 494 // return a "marker todo" by its index 495 this.todo = function(index){ 496 return todos[index]; 497 }; 498 499 // return a "marker value" by its index 500 this.value = function(index){ 501 return values[index]; 502 }; 503 504 // return a marker by its index 505 this.marker = function(index){ 506 return markers[index]; 507 }; 508 509 // store a new marker instead if the default "false" 510 this.setMarker = function(index, marker){ 511 markers[index] = marker; 512 }; 513 514 // link the visible overlay to the logical data (to hide overlays later) 515 this.store = function(cluster, obj, shadow){ 516 store[cluster.ref] = {obj:obj, shadow:shadow}; 517 }; 518 519 // free all objects 520 this.free = function(){ 521 for(var i = 0; i < events.length; i++){ 522 google.maps.event.removeListener(events[i]); 523 } 524 events = []; 525 526 $.each(store, function(key){ 527 flush(key); 528 }); 529 store = {}; 530 531 $.each(todos, function(i){ 532 todos[i] = null; 533 }); 534 todos = []; 535 536 $.each(markers, function(i){ 537 if (markers[i]){ // false = removed 538 markers[i].setMap(null); 539 delete markers[i]; 540 } 541 }); 542 markers = []; 543 544 $.each(values, function(i){ 545 delete values[i]; 546 }); 547 values = []; 548 549 ids = {}; 550 }; 551 552 // link the display function 553 this.filter = function(f){ 554 ffilter = f; 555 redraw(); 556 }; 557 558 // enable/disable the clustering feature 559 this.enable = function(value){ 560 if (enabled != value){ 561 enabled = value; 562 redraw(); 563 } 564 }; 565 566 // link the display function 567 this.display = function(f){ 568 fdisplay = f; 569 }; 570 571 // link the errorfunction 572 this.error = function(f){ 573 ferror = f; 574 }; 575 576 // lock the redraw 577 this.beginUpdate = function () { 578 updating = true; 579 }; 580 581 // unlock the redraw 582 this.endUpdate = function(){ 583 updating = false; 584 if (updated){ 585 redraw(); 586 } 587 }; 588 589 // bind events 590 function main(){ 591 projection = overlay.getProjection(); 592 if (!projection){ 593 setTimeout(function(){ 594 main.apply(that, []); 595 }, 596 25); 597 return; 598 } 599 ready = true; 600 events.push(google.maps.event.addListener(map, "zoom_changed", function(){delayRedraw();})); 601 events.push(google.maps.event.addListener(map, "bounds_changed", function(){delayRedraw();})); 602 redraw(); 603 } 604 605 // flush overlays 606 function flush(key){ 607 if (typeof store[key] === "object"){ // is overlay 608 if (typeof(store[key].obj.setMap) === "function") { 609 store[key].obj.setMap(null); 610 } 611 if (typeof(store[key].obj.remove) === "function") { 612 store[key].obj.remove(); 613 } 614 if (typeof(store[key].shadow.remove) === "function") { 615 store[key].obj.remove(); 616 } 617 if (typeof(store[key].shadow.setMap) === "function") { 618 store[key].shadow.setMap(null); 619 } 620 delete store[key].obj; 621 delete store[key].shadow; 622 } else if (markers[key]){ // marker not removed 623 markers[key].setMap(null); 624 // don't remove the marker object, it may be displayed later 625 } 626 delete store[key]; 627 } 628 629 /** 630 * return the distance between 2 latLng couple into meters 631 * Params : 632 * Lat1, Lng1, Lat2, Lng2 633 * LatLng1, Lat2, Lng2 634 * Lat1, Lng1, LatLng2 635 * LatLng1, LatLng2 636 **/ 637 function distanceInMeter(){ 638 var lat1, lat2, lng1, lng2, e, f, g, h; 639 if (arguments[0] instanceof google.maps.LatLng){ 640 lat1 = arguments[0].lat(); 641 lng1 = arguments[0].lng(); 642 if (arguments[1] instanceof google.maps.LatLng){ 643 lat2 = arguments[1].lat(); 644 lng2 = arguments[1].lng(); 645 } else { 646 lat2 = arguments[1]; 647 lng2 = arguments[2]; 648 } 649 } else { 650 lat1 = arguments[0]; 651 lng1 = arguments[1]; 652 if (arguments[2] instanceof google.maps.LatLng){ 653 lat2 = arguments[2].lat(); 654 lng2 = arguments[2].lng(); 655 } else { 656 lat2 = arguments[2]; 657 lng2 = arguments[3]; 658 } 659 } 660 e = Math.PI*lat1/180; 661 f = Math.PI*lng1/180; 662 g = Math.PI*lat2/180; 663 h = Math.PI*lng2/180; 664 return 1000*6371 * Math.acos(Math.min(Math.cos(e)*Math.cos(g)*Math.cos(f)*Math.cos(h)+Math.cos(e)*Math.sin(f)*Math.cos(g)*Math.sin(h)+Math.sin(e)*Math.sin(g),1)); 665 } 666 667 // extend the visible bounds 668 function extendsMapBounds(){ 669 var radius = distanceInMeter(map.getCenter(), map.getBounds().getNorthEast()), 670 circle = new google.maps.Circle({ 671 center: map.getCenter(), 672 radius: 1.25 * radius // + 25% 673 }); 674 return circle.getBounds(); 675 } 676 677 // return an object where keys are store keys 678 function getStoreKeys(){ 679 var keys = {}, k; 680 for(k in store){ 681 keys[k] = true; 682 } 683 return keys; 684 } 685 686 // async the delay function 687 function delayRedraw(){ 688 clearTimeout(timer); 689 timer = setTimeout(function(){ 690 redraw(); 691 }, 692 25); 693 } 694 695 // generate bounds extended by radius 696 function extendsBounds(latLng) { 697 var p = projection.fromLatLngToDivPixel(latLng), 698 ne = projection.fromDivPixelToLatLng(new google.maps.Point(p.x+radius, p.y-radius)), 699 sw = projection.fromDivPixelToLatLng(new google.maps.Point(p.x-radius, p.y+radius)); 700 return new google.maps.LatLngBounds(sw, ne); 701 } 702 703 // run the clustering process and call the display function 704 function redraw(){ 705 if (updating || redrawing || !ready){ 706 return; 707 } 708 709 var keys = [], used = {}, 710 zoom = map.getZoom(), 711 forceDisabled = (maxZoom !== undef) && (zoom > maxZoom), 712 previousKeys = getStoreKeys(), 713 i, j, k, lat, lng, indexes, previous, check = false, bounds, cluster; 714 715 // reset flag 716 updated = false; 717 718 if (zoom > 3){ 719 // extend the bounds of the visible map to manage clusters near the boundaries 720 bounds = extendsMapBounds(); 721 722 // check contain only if boundaries are valid 723 check = bounds.getSouthWest().lng() < bounds.getNorthEast().lng(); 724 } 725 726 // calculate positions of "visibles" markers (in extended bounds) 727 $.each(todos, function(index, todo){ 728 if (!todo){ // marker removed 729 return; 730 } 731 if (check && (!bounds.contains(todo.options.position))){ 732 return; 733 } 734 if (ffilter && !ffilter(values[index])){ 735 return; 736 } 737 keys.push(index); 738 }); 739 740 // for each "visible" marker, search its neighbors to create a cluster 741 // we can't do a classical "for" loop, because, analysis can bypass a marker while focusing on cluster 742 while(1){ 743 i=0; 744 while(used[i] && (i<keys.length)){ // look for the next marker not used 745 i++; 746 } 747 if (i == keys.length){ 86 748 break; 87 749 } 88 } 89 if (this.empty()){ 90 st = []; 91 } 92 } 93 } 94 750 751 indexes = []; 752 753 if (enabled && !forceDisabled){ 754 do{ 755 previous = indexes; 756 indexes = []; 757 758 if (previous.length){ 759 // re-evaluates center 760 lat = lng = 0; 761 for(k=0; k<previous.length; k++){ 762 lat += todos[ keys[previous[k]] ].options.position.lat(); 763 lng += todos[ keys[previous[k]] ].options.position.lng(); 764 } 765 lat /= previous.length; 766 lng /= previous.length; 767 bounds = extendsBounds(new google.maps.LatLng(lat, lng)); 768 } else { 769 bounds = extendsBounds(todos[ keys[i] ].options.position); 770 } 771 772 for(j=i; j<keys.length; j++){ 773 if (used[j]){ 774 continue; 775 } 776 if (bounds.contains(todos[ keys[j] ].options.position)){ 777 indexes.push(j); 778 } 779 } 780 } while( (previous.length < indexes.length) && (indexes.length > 1) ); 781 } else { 782 for(j=i; j<keys.length; j++){ 783 if (used[j]){ 784 continue; 785 } 786 indexes.push(j); 787 break; 788 } 789 } 790 791 cluster = {latLng:bounds.getCenter(), indexes:[], ref:[]}; 792 for(k=0; k<indexes.length; k++){ 793 used[ indexes[k] ] = true; 794 cluster.indexes.push(keys[indexes[k]]); 795 cluster.ref.push(keys[indexes[k]]); 796 } 797 cluster.ref = cluster.ref.join("-"); 798 799 if (cluster.ref in previousKeys){ // cluster doesn't change 800 delete previousKeys[cluster.ref]; // remove this entry, these still in this array will be removed 801 } else { // cluster is new 802 if (indexes.length === 1){ // alone markers are not stored, so need to keep the key (else, will be displayed every time and marker will blink) 803 store[cluster.ref] = true; 804 } 805 // use a closure to async the display call make faster the process of cle clustering 806 (function(cl){ 807 setTimeout(function(){ 808 fdisplay(cl); // while displaying, will use store to link object 809 }, 1); 810 })(cluster); 811 } 812 } 813 814 // flush the previous overlays which are not still used 815 $.each(previousKeys, function(key){ 816 flush(key); 817 }); 818 redrawing = false; 819 } 820 } 821 822 /** 823 * Class Clusterer 824 * a facade with limited method for external use 825 **/ 826 function Clusterer(id, internalClusterer){ 827 this.id = function(){ 828 return id; 829 }; 830 this.filter = function(f){ 831 internalClusterer.filter(f); 832 }; 833 this.enable = function(){ 834 internalClusterer.enable(true); 835 }; 836 this.disable = function(){ 837 internalClusterer.enable(false); 838 }; 839 this.add = function(marker, todo, lock){ 840 if (!lock) { 841 internalClusterer.beginUpdate(); 842 } 843 internalClusterer.addMarker(marker, todo); 844 if (!lock) { 845 internalClusterer.endUpdate(); 846 } 847 }; 848 this.getById = function(id){ 849 return internalClusterer.getById(id); 850 }; 851 this.clearById = function(id, lock){ 852 if (!lock) { 853 internalClusterer.beginUpdate(); 854 } 855 internalClusterer.clearById(id); 856 if (!lock) { 857 internalClusterer.endUpdate(); 858 } 859 }; 860 } 95 861 /***************************************************************************/ 96 862 /* STORE */ 97 863 /***************************************************************************/ 864 98 865 function Store(){ 99 var store = {}; 866 var store = {}, // name => [id, ...] 867 objects = {}; // id => object 868 869 function ftag(tag){ 870 if (tag){ 871 if (typeof tag === "function"){ 872 return tag; 873 } 874 tag = array(tag); 875 return function(val){ 876 if (val === undef){ 877 return false; 878 } 879 if (typeof val === "object"){ 880 for(var i=0; i<val.length; i++){ 881 if($.inArray(val[i], tag) >= 0){ 882 return true; 883 } 884 } 885 return false; 886 } 887 return $.inArray(val, tag) >= 0; 888 } 889 } 890 } 891 892 function normalize(res) { 893 return { 894 id: res.id, 895 name: res.name, 896 object:res.obj, 897 tag:res.tag, 898 data:res.data 899 }; 900 } 100 901 101 902 /** 102 903 * add a mixed to the store 103 904 **/ 104 this.add = function(name, obj, todo){ 105 name = name.toLowerCase(); 905 this.add = function(args, name, obj, sub){ 906 var todo = args.todo || {}, 907 id = globalId(todo.id); 106 908 if (!store[name]){ 107 909 store[name] = []; 108 910 } 109 store[name].push({obj:obj, tag:ival(todo, 'tag')}); 110 return name + '-' + (store[name].length-1); 111 } 112 113 /** 114 * return a stored mixed 115 **/ 116 this.get = function(name, last, tag){ 117 var i, idx, add; 118 name = name.toLowerCase(); 911 if (id in objects){ // object already exists: remove it 912 this.clearById(id); 913 } 914 objects[id] = {obj:obj, sub:sub, name:name, id:id, tag:todo.tag, data:todo.data}; 915 store[name].push(id); 916 return id; 917 }; 918 919 /** 920 * return a stored object by its id 921 **/ 922 this.getById = function(id, sub, full){ 923 if (id in objects){ 924 if (sub) { 925 return objects[id].sub 926 } else if (full) { 927 return normalize(objects[id]); 928 } 929 return objects[id].obj; 930 931 } 932 return false; 933 }; 934 935 /** 936 * return a stored value 937 **/ 938 this.get = function(name, last, tag, full){ 939 var n, id, check = ftag(tag); 119 940 if (!store[name] || !store[name].length){ 120 941 return null; 121 942 } 122 idx = last ? store[name].length : -1; 123 add = last ? -1 : 1; 124 for(i=0; i<store[name].length; i++){ 125 idx += add; 126 if (store[name][idx]){ 127 if (tag !== undefined) { 128 if ( (store[name][idx].tag === undefined) || ($.inArray(store[name][idx].tag, tag) < 0) ){ 129 continue; 943 n = store[name].length; 944 while(n){ 945 n--; 946 id = store[name][last ? n : store[name].length - n - 1]; 947 if (id && objects[id]){ 948 if (check && !check(objects[id].tag)){ 949 continue; 950 } 951 return full ? normalize(objects[id]) : objects[id].obj; 952 } 953 } 954 return null; 955 }; 956 957 /** 958 * return all stored values 959 **/ 960 this.all = function(name, tag, full){ 961 var result = [], 962 check = ftag(tag), 963 find = function(n){ 964 var i, id; 965 for(i=0; i<store[n].length; i++){ 966 id = store[n][i]; 967 if (id && objects[id]){ 968 if (check && !check(objects[id].tag)){ 969 continue; 970 } 971 result.push(full ? normalize(objects[id]) : objects[id].obj); 972 } 130 973 } 131 } 132 return store[name][idx].obj; 133 } 134 } 135 return null; 136 } 137 138 /** 139 * return all stored mixed 140 **/ 141 this.all = function(name, tag){ 142 var i, result = []; 143 name = name.toLowerCase(); 144 if (!store[name] || !store[name].length){ 145 return result; 146 } 147 for(i=0; i<store[name].length; i++){ 148 if (!store[name][i]){ 149 continue; 150 } 151 if ( (tag !== undefined) && ( (store[name][i].tag === undefined) || ($.inArray(store[name][i].tag, tag) < 0) ) ){ 152 continue; 153 } 154 result.push(store[name][i].obj); 974 }; 975 if (name in store){ 976 find(name); 977 } else if (name === undef){ // internal use only 978 for(name in store){ 979 find(name); 980 } 155 981 } 156 982 return result; 157 } 158 159 /** 160 * return all storation groups 161 **/ 162 this.names = function(){ 163 var name, result = []; 164 for(name in store){ 165 result.push(name); 166 } 167 return result; 168 } 169 170 /** 171 * return an object from its reference 172 **/ 173 this.refToObj = function(ref){ 174 ref = ref.split('-'); // name - idx 175 if ((ref.length == 2) && store[ref[0]] && store[ref[0]][ref[1]]){ 176 return store[ref[0]][ref[1]].obj; 177 } 178 return null; 179 } 180 983 }; 984 985 /** 986 * hide and remove an object 987 **/ 988 function rm(obj){ 989 // Google maps element 990 if (typeof(obj.setMap) === "function") { 991 obj.setMap(null); 992 } 993 // jQuery 994 if (typeof(obj.remove) === "function") { 995 obj.remove(); 996 } 997 // internal (cluster) 998 if (typeof(obj.free) === "function") { 999 obj.free(); 1000 } 1001 obj = null; 1002 } 1003 181 1004 /** 182 1005 * remove one object from the store 183 1006 **/ 184 this.rm = function(name, tag, pop){ 185 var idx, i, tmp; 186 name = name.toLowerCase(); 1007 this.rm = function(name, check, pop){ 1008 var idx, id; 187 1009 if (!store[name]) { 188 1010 return false; 189 1011 } 190 if ( tag !== undefined){1012 if (check){ 191 1013 if (pop){ 192 1014 for(idx = store[name].length - 1; idx >= 0; idx--){ 193 if ( (store[name][idx] !== undefined) && (store[name][idx].tag !== undefined) && ($.inArray(store[name][idx].tag, tag) >= 0) ){ 1015 id = store[name][idx]; 1016 if ( check(objects[id].tag) ){ 194 1017 break; 195 1018 } … … 197 1020 } else { 198 1021 for(idx = 0; idx < store[name].length; idx++){ 199 if ( (store[name][idx] !== undefined) && (store[name][idx].tag !== undefined) && ($.inArray(store[name][idx].tag, tag) >= 0) ){ 1022 id = store[name][idx]; 1023 if (check(objects[id].tag)){ 200 1024 break; 201 1025 } … … 208 1032 return false; 209 1033 } 210 // Google maps element 211 if (typeof(store[name][idx].obj.setMap) === 'function') { 212 store[name][idx].obj.setMap(null); 213 } 214 // jQuery 215 if (typeof(store[name][idx].obj.remove) === 'function') { 216 store[name][idx].obj.remove(); 217 } 218 // internal (cluster) 219 if (typeof(store[name][idx].obj.free) === 'function') { 220 store[name][idx].obj.free(); 221 } 222 delete store[name][idx].obj; 223 if (tag !== undefined){ 224 tmp = []; 225 for(i=0; i<store[name].length; i++){ 226 if (i !== idx){ 227 tmp.push(store[name][i]); 228 } 229 } 230 store[name] = tmp; 231 } else { 232 if (pop) { 233 store[name].pop(); 234 } else { 235 store[name].shift(); 236 } 237 } 238 return true; 239 } 1034 return this.clearById(store[name][idx], idx); 1035 }; 1036 1037 /** 1038 * remove object from the store by its id 1039 **/ 1040 this.clearById = function(id, idx){ 1041 if (id in objects){ 1042 var i, name = objects[id].name; 1043 for(i=0; idx === undef && i<store[name].length; i++){ 1044 if (id === store[name][i]){ 1045 idx = i; 1046 } 1047 } 1048 rm(objects[id].obj); 1049 if(objects[id].sub){ 1050 rm(objects[id].sub); 1051 } 1052 delete objects[id]; 1053 store[name].splice(idx, 1); 1054 return true; 1055 } 1056 return false; 1057 }; 1058 1059 /** 1060 * return an object from a container object in the store by its id 1061 * ! for now, only cluster manage this feature 1062 **/ 1063 this.objGetById = function(id){ 1064 var result; 1065 if (store["clusterer"]) { 1066 for(var idx in store["clusterer"]){ 1067 if ((result = objects[store["clusterer"][idx]].obj.getById(id)) !== false){ 1068 return result; 1069 } 1070 } 1071 } 1072 return false; 1073 }; 1074 1075 /** 1076 * remove object from a container object in the store by its id 1077 * ! for now, only cluster manage this feature 1078 **/ 1079 this.objClearById = function(id){ 1080 if (store["clusterer"]) { 1081 for(var idx in store["clusterer"]){ 1082 if (objects[store["clusterer"][idx]].obj.clearById(id)){ 1083 return true; 1084 } 1085 } 1086 } 1087 return null; 1088 }; 240 1089 241 1090 /** … … 243 1092 **/ 244 1093 this.clear = function(list, last, first, tag){ 245 var k, i, name ;1094 var k, i, name, check = ftag(tag); 246 1095 if (!list || !list.length){ 247 1096 list = []; … … 254 1103 for(i=0; i<list.length; i++){ 255 1104 if (list[i]){ 256 name = list[i] .toLowerCase();1105 name = list[i]; 257 1106 if (!store[name]){ 258 1107 continue; 259 1108 } 260 1109 if (last){ 261 this.rm(name, tag, true);1110 this.rm(name, check, true); 262 1111 } else if (first){ 263 this.rm(name, tag, false); 264 } else { 265 // all 266 while (this.rm(name, tag, false)); 267 } 268 } 269 } 270 } 271 } 272 273 /***************************************************************************/ 274 /* CLUSTERER */ 275 /***************************************************************************/ 276 277 function Clusterer(){ 278 var markers = [], events=[], stored=[], latest=[], redrawing = false, redraw; 279 280 this.events = function(){ 281 for(var i=0; i<arguments.length; i++){ 282 events.push(arguments[i]); 283 } 284 } 285 286 this.startRedraw = function(){ 287 if (!redrawing){ 288 redrawing = true; 289 return true; 290 } 291 return false; 292 } 293 294 this.endRedraw = function(){ 295 redrawing = false; 296 } 297 298 this.redraw = function(){ 299 var i, args = [], that = this; 300 for(i=0; i<arguments.length; i++){ 301 args.push(arguments[i]); 302 } 303 if (this.startRedraw){ 304 redraw.apply(that, args); 305 this.endRedraw(); 306 } else { 307 setTimeout(function(){ 308 that.redraw.apply(that, args); 309 }, 310 50 311 ); 312 } 313 }; 314 315 this.setRedraw = function(fnc){ 316 redraw = fnc; 317 } 318 319 this.store = function(data, obj, shadow){ 320 stored.push({data:data, obj:obj, shadow:shadow}); 321 } 322 323 this.free = function(){ 324 for(var i = 0; i < events.length; i++){ 325 google.maps.event.removeListener(events[i]); 326 } 327 events=[]; 328 this.freeAll(); 329 } 330 331 this.freeIndex = function(i){ 332 if (typeof(stored[i].obj.setMap) === 'function') { 333 stored[i].obj.setMap(null); 334 } 335 if (typeof(stored[i].obj.remove) === 'function') { 336 stored[i].obj.remove(); 337 } 338 if (stored[i].shadow){ // only overlays has shadow 339 if (typeof(stored[i].shadow.remove) === 'function') { 340 stored[i].obj.remove(); 341 } 342 if (typeof(stored[i].shadow.setMap) === 'function') { 343 stored[i].shadow.setMap(null); 344 } 345 delete stored[i].shadow; 346 } 347 delete stored[i].obj; 348 delete stored[i].data; 349 delete stored[i]; 350 } 351 352 this.freeAll = function(){ 353 var i; 354 for(i = 0; i < stored.length; i++){ 355 if (stored[i]) { 356 this.freeIndex(i); 357 } 358 } 359 stored = []; 360 } 361 362 this.freeDiff = function(clusters){ 363 var i, j, same = {}, idx = []; 364 for(i=0; i<clusters.length; i++){ 365 idx.push( clusters[i].idx.join('-') ); 366 } 367 for(i = 0; i < stored.length; i++){ 368 if (!stored[i]) { 369 continue; 370 } 371 j = $.inArray(stored[i].data.idx.join('-'), idx); 372 if (j >= 0){ 373 same[j] = true; 374 } else { 375 this.freeIndex(i); 376 } 377 } 378 return same; 379 } 380 381 this.add = function(latLng, marker){ 382 markers.push({latLng:latLng, marker:marker}); 383 } 384 385 this.get = function(i){ 386 return markers[i]; 387 } 388 389 this.clusters = function(map, radius, maxZoom, force){ 390 var proj = map.getProjection(), 391 nwP = proj.fromLatLngToPoint( 392 new google.maps.LatLng( 393 map.getBounds().getNorthEast().lat(), 394 map.getBounds().getSouthWest().lng() 395 ) 396 ), 397 i, j, j2, p, x, y, k, k2, 398 z = map.getZoom(), 399 pos = {}, 400 saved = {}, 401 unik = {}, 402 clusters = [], 403 cluster, 404 chk, 405 lat, lng, keys, cnt, 406 bounds = map.getBounds(), 407 noClusters = maxZoom && (maxZoom <= map.getZoom()), 408 chkContain = map.getZoom() > 2; 409 410 cnt = 0; 411 keys = {}; 412 for(i = 0; i < markers.length; i++){ 413 if (chkContain && !bounds.contains(markers[i].latLng)){ 414 continue; 415 } 416 p = proj.fromLatLngToPoint(markers[i].latLng); 417 pos[i] = [ 418 Math.floor((p.x - nwP.x) * Math.pow(2, z)), 419 Math.floor((p.y - nwP.y) * Math.pow(2, z)) 420 ]; 421 keys[i] = true; 422 cnt++; 423 } 424 // check if visible markers have changed 425 if (!force && !noClusters){ 426 for(k = 0; k < latest.length; k++){ 427 if( k in keys ){ 428 cnt--; 429 } else { 430 break; 431 } 432 } 433 if (!cnt){ 434 return false; // no change 435 } 436 } 437 438 // save current keys to check later if an update has been done 439 latest = keys; 440 441 keys = []; 442 for(i in pos){ 443 x = pos[i][0]; 444 y = pos[i][1]; 445 if ( !(x in saved) ){ 446 saved[x] = {}; 447 } 448 if (!( y in saved[x]) ) { 449 saved[x][y] = i; 450 unik[i] = {}; 451 keys.push(i); 452 } 453 unik[ saved[x][y] ][i] = true; 454 } 455 radius = Math.pow(radius, 2); 456 delete(saved); 457 458 k = 0; 459 while(1){ 460 while((k <keys.length) && !(keys[k] in unik)){ 461 k++; 462 } 463 if (k == keys.length){ 464 break; 465 } 466 i = keys[k]; 467 lat = pos[i][0]; 468 lng = pos[i][1]; 469 saved = null; 470 471 472 if (noClusters){ 473 saved = {lat:lat, lng:lng, idx:[i]}; 474 } else { 475 do{ 476 cluster = {lat:0, lng:0, idx:[]}; 477 for(k2 = k; k2<keys.length; k2++){ 478 if (!(keys[k2] in unik)){ 479 continue; 480 } 481 j = keys[k2]; 482 if ( Math.pow(lat - pos[j][0], 2) + Math.pow(lng-pos[j][1], 2) <= radius ){ 483 for(j2 in unik[j]){ 484 cluster.lat += markers[j2].latLng.lat(); 485 cluster.lng += markers[j2].latLng.lng(); 486 cluster.idx.push(j2); 487 } 488 } 489 } 490 cluster.lat /= cluster.idx.length; 491 cluster.lng /= cluster.idx.length; 492 if (!saved){ 493 chk = cluster.idx.length > 1; 494 saved = cluster; 495 } else { 496 chk = cluster.idx.length > saved.idx.length; 497 if (chk){ 498 saved = cluster; 499 } 500 } 501 if (chk){ 502 p = proj.fromLatLngToPoint( new google.maps.LatLng(saved.lat, saved.lng) ); 503 lat = Math.floor((p.x - nwP.x) * Math.pow(2, z)); 504 lng = Math.floor((p.y - nwP.y) * Math.pow(2, z)); 505 } 506 } while(chk); 507 } 508 509 for(k2 = 0; k2 < saved.idx.length; k2++){ 510 if (saved.idx[k2] in unik){ 511 delete(unik[saved.idx[k2]]); 512 } 513 } 514 clusters.push(saved); 515 } 516 return clusters; 517 } 518 519 this.getBounds = function(){ 520 var i, bounds = new google.maps.LatLngBounds(); 521 for(i=0; i<markers.length; i++){ 522 bounds.extend(markers[i].latLng); 523 } 524 return bounds; 525 } 526 } 527 1112 this.rm(name, check, false); 1113 } else { // all 1114 while(this.rm(name, check, false)); 1115 } 1116 } 1117 } 1118 }; 1119 } 1120 528 1121 /***************************************************************************/ 529 1122 /* GMAP3 GLOBALS */ 530 1123 /***************************************************************************/ 531 1124 532 var _default = { 533 verbose:false, 534 queryLimit:{ 535 attempt:5, 536 delay:250, // setTimeout(..., delay + random); 537 random:250 538 }, 539 init:{ 540 mapTypeId : google.maps.MapTypeId.ROADMAP, 541 center:[46.578498,2.457275], 542 zoom: 2 543 }, 544 classes:{ 545 Map : google.maps.Map, 546 Marker : google.maps.Marker, 547 InfoWindow : google.maps.InfoWindow, 548 Circle : google.maps.Circle, 549 Rectangle : google.maps.Rectangle, 550 OverlayView : google.maps.OverlayView, 551 StreetViewPanorama: google.maps.StreetViewPanorama, 552 KmlLayer : google.maps.KmlLayer, 553 TrafficLayer : google.maps.TrafficLayer, 554 BicyclingLayer : google.maps.BicyclingLayer, 555 GroundOverlay : google.maps.GroundOverlay, 556 StyledMapType : google.maps.StyledMapType 557 } 558 }, 559 _properties = ['events','onces','options','apply', 'callback', 'data', 'tag'], 560 _noInit = ['init', 'geolatlng', 'getlatlng', 'getroute', 'getelevation', 'getdistance', 'addstyledmap', 'setdefault', 'destroy'], 561 _directs = ['get'], 562 geocoder = directionsService = elevationService = maxZoomService = distanceMatrixService = null; 563 564 function setDefault(values){ 565 for(var k in values){ 566 if (typeof(_default[k]) === 'object'){ 567 _default[k] = $.extend({}, _default[k], values[k]); 568 } else { 569 _default[k] = values[k]; 570 } 571 } 572 } 573 574 function autoInit(iname){ 575 if (!iname){ 576 return true; 577 } 578 for(var i = 0; i < _noInit.length; i++){ 579 if (_noInit[i] === iname) { 580 return false; 581 } 582 } 583 return true; 584 } 585 586 587 /** 588 * return true if action has to be executed directly 589 **/ 590 function isDirect (todo){ 591 var action = ival(todo, 'action'); 592 for(var i = 0; i < _directs.length; i++){ 593 if (_directs[i] === action) { 594 return true; 595 } 596 } 597 return false; 598 } 599 600 //-----------------------------------------------------------------------// 601 // Objects tools 602 //-----------------------------------------------------------------------// 603 604 /** 605 * return the real key by an insensitive seach 606 **/ 607 function ikey (object, key){ 608 if (key.toLowerCase){ 609 key = key.toLowerCase(); 610 for(var k in object){ 611 if (k.toLowerCase && (k.toLowerCase() == key)) { 612 return k; 613 } 614 } 615 } 616 return false; 617 } 618 619 /** 620 * return the value of real key by an insensitive seach 621 **/ 622 function ival (object, key, def){ 623 var k = ikey(object, key); 624 return k ? object[k] : def; 625 } 626 627 /** 628 * return true if at least one key is set in object 629 * nb: keys in lowercase 630 **/ 631 function hasKey (object, keys){ 632 var n, k; 633 if (!object || !keys) { 634 return false; 635 } 636 keys = array(keys); 637 for(n in object){ 638 if (n.toLowerCase){ 639 n = n.toLowerCase(); 640 for(k in keys){ 641 if (n == keys[k]) { 642 return true; 643 } 644 } 645 } 646 } 647 return false; 648 } 649 650 /** 651 * return a standard object 652 * nb: include in lowercase 653 **/ 654 function extractObject (todo, include, result/* = {} */){ 655 if (hasKey(todo, _properties) || hasKey(todo, include)){ // #1 classical object definition 656 var i, k; 657 // get defined properties values from todo 658 for(i=0; i<_properties.length; i++){ 659 k = ikey(todo, _properties[i]); 660 result[ _properties[i] ] = k ? todo[k] : {}; 661 } 662 if (include && include.length){ 663 for(i=0; i<include.length; i++){ 664 if(k = ikey(todo, include[i])){ 665 result[ include[i] ] = todo[k]; 666 } 667 } 668 } 669 return result; 670 } else { // #2 simplified object (all excepted "action" are options properties) 671 result.options= {}; 672 for(k in todo){ 673 if (k !== 'action'){ 674 result.options[k] = todo[k]; 675 } 676 } 677 return result; 678 } 679 } 680 681 /** 682 * identify object from object list or parameters list : [ objectName:{data} ] or [ otherObject:{}, ] or [ object properties ] 683 * nb: include, exclude in lowercase 684 **/ 685 function getObject(name, todo, include, exclude){ 686 var iname = ikey(todo, name), 687 i, result = {}, keys=['map']; 688 // include callback from high level 689 result['callback'] = ival(todo, 'callback'); 690 include = array(include); 691 exclude = array(exclude); 692 if (iname) { 693 return extractObject(todo[iname], include, result); 694 } 695 if (exclude && exclude.length){ 696 for(i=0; i<exclude.length; i++) { 697 keys.push(exclude[i]); 698 } 699 } 700 if (!hasKey(todo, keys)){ 701 result = extractObject(todo, include, result); 702 } 703 // initialize missing properties 704 for(i=0; i<_properties.length; i++){ 705 if (_properties[i] in result){ 706 continue; 707 } 708 result[ _properties[i] ] = {}; 709 } 710 return result; 711 } 712 1125 var services = {}, 1126 geocoderCache = new GeocoderCache(); 1127 713 1128 //-----------------------------------------------------------------------// 714 1129 // Service tools 715 1130 //-----------------------------------------------------------------------// 716 717 function ge tGeocoder(){718 if (! geocoder) {719 geocoder = new google.maps.Geocoder();720 } 721 return geocoder;722 } 723 724 function getDirectionsService(){725 if (! directionsService) {726 directionsService = new google.maps.DirectionsService();727 } 728 return directionsService;729 } 730 731 function getElevationService(){732 if (! elevationService) {733 elevationService = new google.maps.ElevationService();734 } 735 return elevationService;736 } 737 738 function getMaxZoomService(){739 if (! maxZoomService) {740 maxZoomService = new google.maps.MaxZoomService();741 } 742 return maxZoomService;743 } 744 745 function getDistanceMatrixService(){746 if (! distanceMatrixService) {747 distanceMatrixService = new google.maps.DistanceMatrixService();748 } 749 return distanceMatrixService;750 } 751 1131 1132 function geocoder(){ 1133 if (!services.geocoder) { 1134 services.geocoder = new google.maps.Geocoder(); 1135 } 1136 return services.geocoder; 1137 } 1138 1139 function directionsService(){ 1140 if (!services.directionsService) { 1141 services.directionsService = new google.maps.DirectionsService(); 1142 } 1143 return services.directionsService; 1144 } 1145 1146 function elevationService(){ 1147 if (!services.elevationService) { 1148 services.elevationService = new google.maps.ElevationService(); 1149 } 1150 return services.elevationService; 1151 } 1152 1153 function maxZoomService(){ 1154 if (!services.maxZoomService) { 1155 services.maxZoomService = new google.maps.MaxZoomService(); 1156 } 1157 return services.maxZoomService; 1158 } 1159 1160 function distanceMatrixService(){ 1161 if (!services.distanceMatrixService) { 1162 services.distanceMatrixService = new google.maps.DistanceMatrixService(); 1163 } 1164 return services.distanceMatrixService; 1165 } 1166 752 1167 //-----------------------------------------------------------------------// 753 1168 // Unit tools 754 1169 //-----------------------------------------------------------------------// 755 1170 1171 function error(){ 1172 if (defaults.verbose){ 1173 var i, err = []; 1174 if (window.console && (typeof console.error === "function") ){ 1175 for(i=0; i<arguments.length; i++){ 1176 err.push(arguments[i]); 1177 } 1178 console.error.apply(console, err); 1179 } else { 1180 err = ""; 1181 for(i=0; i<arguments.length; i++){ 1182 err += arguments[i].toString() + " " ; 1183 } 1184 alert(err); 1185 } 1186 } 1187 } 1188 756 1189 /** 757 1190 * return true if mixed is usable as number 758 1191 **/ 759 1192 function numeric(mixed){ 760 return (typeof(mixed) === 'number' || typeof(mixed) === 'string') && mixed !== ''&& !isNaN(mixed);761 } 762 763 /**1193 return (typeof(mixed) === "number" || typeof(mixed) === "string") && mixed !== "" && !isNaN(mixed); 1194 } 1195 1196 /** 764 1197 * convert data to array 765 1198 **/ 766 1199 function array(mixed){ 767 1200 var k, a = []; 768 if (mixed !== undef ined){769 if (typeof(mixed) === 'object'){770 if (typeof(mixed.length) === 'number') {1201 if (mixed !== undef){ 1202 if (typeof(mixed) === "object"){ 1203 if (typeof(mixed.length) === "number") { 771 1204 a = mixed; 772 1205 } else { … … 787 1220 function toLatLng (mixed, emptyReturnMixed, noFlat){ 788 1221 var empty = emptyReturnMixed ? mixed : null; 789 if (!mixed || (typeof (mixed) === 'string')){1222 if (!mixed || (typeof mixed === "string")){ 790 1223 return empty; 791 1224 } … … 795 1228 } 796 1229 // google.maps.LatLng object 797 if ( typeof(mixed.lat) === 'function') {1230 if (mixed instanceof google.maps.LatLng) { 798 1231 return mixed; 799 1232 } … … 803 1236 } 804 1237 // [X, Y] object 805 else if ( !noFlat && mixed.length){ // and "no flat" object allowed1238 else if ( !noFlat && $.isArray(mixed)){ 806 1239 if ( !numeric(mixed[0]) || !numeric(mixed[1]) ) { 807 1240 return empty; … … 815 1248 * convert mixed [ sw, ne ] object by google.maps.LatLngBounds 816 1249 **/ 817 function toLatLngBounds(mixed, flatAllowed, emptyReturnMixed){ 818 var ne, sw, empty; 819 if (!mixed) { 820 return null; 821 } 822 empty = emptyReturnMixed ? mixed : null; 823 if (typeof(mixed.getCenter) === 'function') { 824 return mixed; 825 } 826 if (mixed.length){ 1250 function toLatLngBounds(mixed){ 1251 var ne, sw; 1252 if (!mixed || mixed instanceof google.maps.LatLngBounds) { 1253 return mixed || null; 1254 } 1255 if ($.isArray(mixed)){ 827 1256 if (mixed.length == 2){ 828 1257 ne = toLatLng(mixed[0]); … … 833 1262 } 834 1263 } else { 835 if ( ( 'ne' in mixed) && ('sw'in mixed) ){1264 if ( ("ne" in mixed) && ("sw" in mixed) ){ 836 1265 ne = toLatLng(mixed.ne); 837 1266 sw = toLatLng(mixed.sw); 838 } else if ( ( 'n' in mixed) && ('e' in mixed) && ('s' in mixed) && ('w'in mixed) ){1267 } else if ( ("n" in mixed) && ("e" in mixed) && ("s" in mixed) && ("w" in mixed) ){ 839 1268 ne = toLatLng([mixed.n, mixed.e]); 840 1269 sw = toLatLng([mixed.s, mixed.w]); … … 844 1273 return new google.maps.LatLngBounds(sw, ne); 845 1274 } 846 return empty; 1275 return null; 1276 } 1277 1278 /** 1279 * resolveLatLng 1280 **/ 1281 function resolveLatLng(ctx, method, runLatLng, args, attempt){ 1282 var latLng = runLatLng ? toLatLng(args.todo, false, true) : false, 1283 conf = latLng ? {latLng:latLng} : (args.todo.address ? (typeof(args.todo.address) === "string" ? {address:args.todo.address} : args.todo.address) : false), 1284 cache = conf ? geocoderCache.get(conf) : false, 1285 that = this; 1286 if (conf){ 1287 attempt = attempt || 0; // convert undefined to int 1288 if (cache){ 1289 args.latLng = cache.results[0].geometry.location; 1290 args.results = cache.results; 1291 args.status = cache.status; 1292 method.apply(ctx, [args]); 1293 } else { 1294 if (conf.location){ 1295 conf.location = toLatLng(conf.location); 1296 } 1297 if (conf.bounds){ 1298 conf.bounds = toLatLngBounds(conf.bounds); 1299 } 1300 geocoder().geocode( 1301 conf, 1302 function(results, status) { 1303 if (status === google.maps.GeocoderStatus.OK){ 1304 geocoderCache.store(conf, {results:results, status:status}); 1305 args.latLng = results[0].geometry.location; 1306 args.results = results; 1307 args.status = status; 1308 method.apply(ctx, [args]); 1309 } else if ( (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) && (attempt < defaults.queryLimit.attempt) ){ 1310 setTimeout( 1311 function(){ 1312 resolveLatLng.apply(that, [ctx, method, runLatLng, args, attempt+1]); 1313 }, 1314 defaults.queryLimit.delay + Math.floor(Math.random() * defaults.queryLimit.random) 1315 ); 1316 } else { 1317 error("geocode failed", status, conf); 1318 args.latLng = args.results = false; 1319 args.status = status; 1320 method.apply(ctx, [args]); 1321 } 1322 } 1323 ); 1324 } 1325 } else { 1326 args.latLng = toLatLng(args.todo, false, true); 1327 method.apply(ctx, [args]); 1328 } 1329 } 1330 1331 function resolveAllLatLng(list, ctx, method, args){ 1332 var that = this, i = -1; 1333 1334 function resolve(){ 1335 // look for next address to resolve 1336 do{ 1337 i++; 1338 }while( (i < list.length) && !("address" in list[i]) ); 1339 1340 // no address found, so run method 1341 if (i >= list.length){ 1342 method.apply(ctx, [args]); 1343 return; 1344 } 1345 1346 resolveLatLng( 1347 that, 1348 function(args){ 1349 delete args.todo; 1350 $.extend(list[i], args); 1351 resolve.apply(that, []); // resolve next (using apply avoid too much recursion) 1352 }, 1353 true, 1354 {todo:list[i]} 1355 ); 1356 } 1357 resolve(); 1358 } 1359 1360 /** 1361 * geolocalise the user and return a LatLng 1362 **/ 1363 function geoloc(ctx, method, args){ 1364 var is_echo = false; // sometime, a kind of echo appear, this trick will notice once the first call is run to ignore the next one 1365 if (navigator && navigator.geolocation){ 1366 navigator.geolocation.getCurrentPosition( 1367 function(pos) { 1368 if (is_echo){ 1369 return; 1370 } 1371 is_echo = true; 1372 args.latLng = new google.maps.LatLng(pos.coords.latitude,pos.coords.longitude); 1373 method.apply(ctx, [args]); 1374 }, 1375 function() { 1376 if (is_echo){ 1377 return; 1378 } 1379 is_echo = true; 1380 args.latLng = false; 1381 method.apply(ctx, [args]); 1382 }, 1383 args.opts.getCurrentPosition 1384 ); 1385 } else { 1386 args.latLng = false; 1387 method.apply(ctx, [args]); 1388 } 847 1389 } 848 1390 … … 852 1394 853 1395 function Gmap3($this){ 854 855 var stack = new Stack(), 856 store = new Store(), 857 map = null, 858 styles = {}, 859 running = false; 1396 var that = this, 1397 stack = new Stack(), 1398 store = new Store(), 1399 map = null, 1400 task; 860 1401 861 1402 //-----------------------------------------------------------------------// 862 1403 // Stack tools 863 1404 //-----------------------------------------------------------------------// 864 1405 865 1406 /** 866 1407 * store actions to execute in a stack manager … … 868 1409 this._plan = function(list){ 869 1410 for(var k = 0; k < list.length; k++) { 870 stack.add(list[k]); 871 } 872 this._run(); 1411 stack.add(new Task(that, end, list[k])); 1412 } 1413 run(); 1414 }; 1415 1416 /** 1417 * if not running, start next action in stack 1418 **/ 1419 function run(){ 1420 if (!task && (task = stack.get())){ 1421 task.run(); 1422 } 1423 } 1424 1425 /** 1426 * called when action in finished, to acknoledge the current in stack and start next one 1427 **/ 1428 function end(){ 1429 task = null; 1430 stack.ack(); 1431 run.call(that); // restart to high level scope 1432 } 1433 1434 //-----------------------------------------------------------------------// 1435 // Tools 1436 //-----------------------------------------------------------------------// 1437 1438 /** 1439 * execute callback functions 1440 **/ 1441 function callback(args){ 1442 var i, params = []; 1443 for(i=1; i<arguments.length; i++){ 1444 params.push(arguments[i]); 1445 } 1446 if (typeof args.todo.callback === "function") { 1447 args.todo.callback.apply($this, params); 1448 } else if (typeof args.todo.callback === "object") { 1449 $.each(args.todo.callback, function(i, cb){ 1450 if (typeof cb === "function") { 1451 cb.apply($this, params); 1452 } 1453 }); 1454 } 1455 } 1456 1457 /** 1458 * execute ending functions 1459 **/ 1460 function manageEnd(args, obj, id){ 1461 if (id){ 1462 attachEvents($this, args, obj, id); 1463 } 1464 callback(args, obj); 1465 task.ack(obj); 1466 } 1467 1468 /** 1469 * initialize the map if not yet initialized 1470 **/ 1471 function newMap(latLng, args){ 1472 args = args || {}; 1473 if (map) { 1474 if (args.todo && args.todo.options){ 1475 map.setOptions(args.todo.options); 1476 } 1477 } else { 1478 var opts = args.opts || $.extend(true, {}, defaults.map, args.todo && args.todo.options ? args.todo.options : {}); 1479 opts.center = latLng || toLatLng(opts.center); 1480 map = new defaults.classes.Map($this.get(0), opts); 1481 } 873 1482 } 874 1483 875 /** 876 * store one action to execute in a stack manager after the current 877 **/ 878 this._planNext = function(todo){ 879 stack.addNext(todo); 880 } 881 882 /** 883 * execute action directly 884 **/ 885 this._direct = function(todo){ 886 var action = ival(todo, 'action'); 887 return this[action]($.extend({}, action in _default ? _default[action] : {}, todo.args ? todo.args : todo)); 888 } 889 890 /** 891 * called when action in finished, to acknoledge the current in stack and start next one 892 **/ 893 this._end = function(){ 894 running = false; 895 stack.ack(); 896 this._run(); 897 }, 898 /** 899 * if not running, start next action in stack 900 **/ 901 this._run = function(){ 902 if (running) { 903 return; 904 } 905 var todo = stack.get(); 906 if (!todo) { 907 return; 908 } 909 running = true; 910 this._proceed(todo); 911 } 912 913 //-----------------------------------------------------------------------// 914 // Call tools 915 //-----------------------------------------------------------------------// 916 917 /** 918 * run the appropriated function 919 **/ 920 this._proceed = function(todo){ 921 todo = todo || {}; 922 var action = ival(todo, 'action') || 'init', 923 iaction = action.toLowerCase(), 924 ok = true, 925 target = ival(todo, 'target'), 926 args = ival(todo, 'args'), 927 out; 928 // check if init should be run automatically 929 if ( !map && autoInit(iaction) ){ 930 this.init($.extend({}, _default.init, todo.args && todo.args.map ? todo.args.map : todo.map ? todo.map : {}), true); 931 } 932 933 // gmap3 function 934 if (!target && !args && (iaction in this) && (typeof(this[iaction]) === 'function')){ 935 this[iaction]($.extend({}, iaction in _default ? _default[iaction] : {}, todo.args ? todo.args : todo)); // call fnc and extends defaults data 936 } else { 937 // "target" object function 938 if (target && (typeof(target) === 'object')){ 939 if (ok = (typeof(target[action]) === 'function')){ 940 out = target[action].apply(target, todo.args ? todo.args : []); 941 } 942 // google.maps.Map direct function : no result so not rewrited, directly wrapped using array "args" as parameters (ie. setOptions, addMapType, ...) 943 } else if (map){ 944 if (ok = (typeof(map[action]) === 'function')){ 945 out = map[action].apply(map, todo.args ? todo.args : [] ); 946 } 947 } 948 if (!ok && _default.verbose) { 949 alert("unknown action : " + action); 950 } 951 this._callback(out, todo); 952 this._end(); 953 } 954 } 955 956 /** 957 * returns the geographical coordinates from an address and call internal or given method 958 **/ 959 this._resolveLatLng = function(todo, method, all, attempt){ 960 var address = ival(todo, 'address'), 961 params, 962 that = this, 963 fnc = typeof(method) === 'function' ? method : that[method]; 964 if ( address ){ 965 if (!attempt){ // convert undefined to int 966 attempt = 0; 967 } 968 if (typeof(address) === 'object'){ 969 params = address; 970 } else { 971 params = {'address': address}; 972 } 973 getGeocoder().geocode( 974 params, 975 function(results, status) { 976 if (status === google.maps.GeocoderStatus.OK){ 977 fnc.apply(that, [todo, all ? results : results[0].geometry.location]); 978 } else if ( (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) && (attempt < _default.queryLimit.attempt) ){ 979 setTimeout(function(){ 980 that._resolveLatLng(todo, method, all, attempt+1); 981 }, 982 _default.queryLimit.delay + Math.floor(Math.random() * _default.queryLimit.random) 983 ); 984 } else { 985 if (_default.verbose){ 986 alert('Geocode error : ' + status); 987 } 988 fnc.apply(that, [todo, false]);; 989 } 990 } 991 ); 992 } else { 993 fnc.apply(that, [todo, toLatLng(todo, false, true)]); 994 } 995 } 996 997 /** 998 * returns the geographical coordinates from an array of object using "address" and call internal method 999 **/ 1000 this._resolveAllLatLng = function(todo, property, method){ 1001 var that = this, 1002 i = -1, 1003 solveNext = function(){ 1004 do{ 1005 i++; 1006 }while( (i < todo[property].length) && !('address' in todo[property][i]) ); 1007 if (i < todo[property].length){ 1008 (function(todo){ 1009 that._resolveLatLng( 1010 todo, 1011 function(todo, latLng){ 1012 todo.latLng = latLng; 1013 solveNext.apply(that, []); // solve next or execute exit method 1014 } 1015 ); 1016 })(todo[property][i]); 1017 } else { 1018 that[method](todo); 1019 } 1020 }; 1021 solveNext(); 1022 } 1023 1024 /** 1025 * call a function of framework or google map object of the instance 1026 **/ 1027 this._call = function(/* fncName [, ...] */){ 1028 var i, fname = arguments[0], args = []; 1029 if ( !arguments.length || !map || (typeof(map[fname]) !== 'function') ){ 1030 return; 1031 } 1032 for(i=1; i<arguments.length; i++){ 1033 args.push(arguments[i]); 1034 } 1035 return map[fname].apply(map, args); 1036 } 1037 1038 /** 1039 * init if not and manage map subcall (zoom, center) 1040 **/ 1041 this._subcall = function(todo, latLng){ 1042 var opts = {}; 1043 if (!todo.map) return; 1044 if (!latLng) { 1045 latLng = ival(todo.map, 'latlng'); 1046 } 1047 if (!map){ 1048 if (latLng) { 1049 opts = {center:latLng}; 1050 } 1051 this.init($.extend({}, todo.map, opts), true); 1052 } else { 1053 if (todo.map.center && latLng){ 1054 this._call("setCenter", latLng); 1055 } 1056 if (todo.map.zoom !== undefined){ 1057 this._call("setZoom", todo.map.zoom); 1058 } 1059 if (todo.map.mapTypeId !== undefined){ 1060 this._call("setMapTypeId", todo.map.mapTypeId); 1061 } 1062 } 1063 } 1064 1065 /** 1066 * attach an event to a sender 1067 **/ 1068 this._attachEvent = function(sender, name, fnc, data, once){ 1069 google.maps.event['addListener'+(once?'Once':'')](sender, name, function(event) { 1070 fnc.apply($this, [sender, event, data]); 1071 }); 1072 } 1073 1074 /** 1075 * attach events from a container to a sender 1076 * todo[ 1077 * events => { eventName => function, } 1078 * onces => { eventName => function, } 1079 * data => mixed data 1080 * ] 1081 **/ 1082 this._attachEvents = function(sender, todo){ 1083 var name; 1084 if (!todo) { 1085 return 1086 } 1087 if (todo.events){ 1088 for(name in todo.events){ 1089 if (typeof(todo.events[name]) === 'function'){ 1090 this._attachEvent(sender, name, todo.events[name], todo.data, false); 1091 } 1092 } 1093 } 1094 if (todo.onces){ 1095 for(name in todo.onces){ 1096 if (typeof(todo.onces[name]) === 'function'){ 1097 this._attachEvent(sender, name, todo.onces[name], todo.data, true); 1098 } 1099 } 1100 } 1101 } 1102 1103 /** 1104 * execute callback functions 1105 **/ 1106 this._callback = function(result, todo){ 1107 if (typeof(todo.callback) === 'function') { 1108 todo.callback.apply($this, [result]); 1109 } else if (typeof(todo.callback) === 'object') { 1110 for(var i=0; i<todo.callback.length; i++){ 1111 if (typeof(todo.callback[i]) === 'function') { 1112 todo.callback[k].apply($this, [result]); 1113 } 1114 } 1115 } 1116 } 1117 1118 /** 1119 * execute ending functions 1120 **/ 1121 this._manageEnd = function(result, todo, internal){ 1122 var i, apply; 1123 if (result && (typeof(result) === 'object')){ 1124 // attach events 1125 this._attachEvents(result, todo); 1126 // execute "apply" 1127 if (todo.apply && todo.apply.length){ 1128 for(i=0; i<todo.apply.length; i++){ 1129 apply = todo.apply[i]; 1130 // need an existing "action" function in the result object 1131 if(!apply.action || (typeof(result[apply.action]) !== 'function') ) { 1132 continue; 1133 } 1134 if (apply.args) { 1135 result[apply.action].apply(result, apply.args); 1136 } else { 1137 result[apply.action](); 1138 } 1139 } 1140 } 1141 } 1142 if (!internal) { 1143 this._callback(result, todo); 1144 this._end(); 1145 } 1146 } 1147 1148 //-----------------------------------------------------------------------// 1149 // gmap3 functions 1150 //-----------------------------------------------------------------------// 1484 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 1485 => function with latLng resolution 1486 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 1487 1488 /** 1489 * Initialize google.maps.Map object 1490 **/ 1491 this.map = function(args){ 1492 newMap(args.latLng, args); 1493 attachEvents($this, args, map); 1494 manageEnd(args, map); 1495 }; 1151 1496 1152 1497 /** 1153 1498 * destroy an existing instance 1154 1499 **/ 1155 this.destroy = function(todo){ 1156 var k; 1500 this.destroy = function(args){ 1157 1501 store.clear(); 1158 1502 $this.empty(); 1159 for(k in styles){1160 delete styles[ k ];1161 }1162 styles = {};1163 1503 if (map){ 1164 delete map; 1165 } 1166 this._callback(null, todo); 1167 this._end(); 1168 } 1169 1170 /** 1171 * Initialize google.maps.Map object 1172 **/ 1173 this.init = function(todo, internal){ 1174 var o, k, opts; 1175 if (map) { // already initialized 1176 return this._end(); 1177 } 1178 1179 o = getObject('map', todo); 1180 if ( (typeof(o.options.center) === 'boolean') && o.options.center) { 1181 return false; // wait for an address resolution 1182 } 1183 opts = $.extend({}, _default.init, o.options); 1184 if (!opts.center) { 1185 opts.center = [_default.init.center.lat, _default.init.center.lng]; 1186 } 1187 opts.center = toLatLng(opts.center); 1188 map = new _default.classes.Map($this.get(0), opts); 1189 1190 // add previous added styles 1191 for(k in styles) { 1192 map.mapTypes.set(k, styles[k]); 1193 } 1194 1195 this._manageEnd(map, o, internal); 1196 return true; 1197 } 1198 1199 /** 1200 * returns the geographical coordinates from an address 1201 **/ 1202 this.getlatlng = function(todo){ 1203 this._resolveLatLng(todo, '_getLatLng', true); 1204 }, 1205 1206 this._getLatLng = function(todo, results){ 1207 this._manageEnd(results, todo); 1208 }, 1209 1210 1211 /** 1212 * returns address from latlng 1213 **/ 1214 this.getaddress = function(todo, attempt){ 1215 var latLng = toLatLng(todo, false, true), 1216 address = ival(todo, 'address'), 1217 params = latLng ? {latLng:latLng} : ( address ? (typeof(address) === 'string' ? {address:address} : address) : null), 1218 callback = ival(todo, 'callback'), 1219 that = this; 1220 if (!attempt){ // convert undefined to int 1221 attempt = 0; 1222 } 1223 if (params && typeof(callback) === 'function') { 1224 getGeocoder().geocode( 1225 params, 1226 function(results, status) { 1227 if ( (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) && (attempt < _default.queryLimit.attempt) ){ 1228 setTimeout(function(){ 1229 that.getaddress(todo, attempt+1); 1230 }, 1231 _default.queryLimit.delay + Math.floor(Math.random() * _default.queryLimit.random) 1232 ); 1504 map = null; 1505 } 1506 manageEnd(args, true); 1507 }; 1508 1509 /** 1510 * add an infowindow 1511 **/ 1512 this.infowindow = function(args){ 1513 var objs = [], multiple = "values" in args.todo; 1514 if (!multiple){ 1515 if (args.latLng) { 1516 args.opts.position = args.latLng; 1517 } else if (args.opts.position){ 1518 args.opts.position = toLatLng(args.opts.position); 1519 } 1520 args.todo.values = [{options:args.opts}]; 1521 } 1522 $.each(args.todo.values, function(i, value){ 1523 var id, obj, todo = tuple(args, value); 1524 if (!map){ 1525 newMap(todo.options.position); 1526 } 1527 obj = new defaults.classes.InfoWindow(todo.options); 1528 if (obj && ((todo.open === undef) || todo.open)){ 1529 if (multiple){ 1530 obj.open(map, todo.anchor ? todo.anchor : undef); 1531 } else { 1532 obj.open(map, todo.anchor ? todo.anchor : (args.latLng ? undef : (args.session.marker ? args.session.marker : undef))); 1533 } 1534 } 1535 objs.push(obj); 1536 id = store.add({todo:todo}, "infowindow", obj); 1537 attachEvents($this, {todo:todo}, obj, id); 1538 }); 1539 manageEnd(args, multiple ? objs : objs[0]); 1540 }; 1541 1542 /** 1543 * add a circle 1544 **/ 1545 this.circle = function(args){ 1546 var objs = [], multiple = "values" in args.todo; 1547 if (!multiple){ 1548 args.opts.center = args.latLng || toLatLng(args.opts.center); 1549 args.todo.values = [{options:args.opts}]; 1550 } 1551 if (!args.todo.values.length){ 1552 manageEnd(args, false); 1553 return; 1554 } 1555 $.each(args.todo.values, function(i, value){ 1556 var id, obj, todo = tuple(args, value); 1557 todo.options.center = todo.options.center ? toLatLng(todo.options.center) : toLatLng(value); 1558 if (!map){ 1559 newMap(todo.options.center); 1560 } 1561 todo.options.map = map; 1562 obj = new defaults.classes.Circle(todo.options); 1563 objs.push(obj); 1564 id = store.add({todo:todo}, "circle", obj); 1565 attachEvents($this, {todo:todo}, obj, id); 1566 }); 1567 manageEnd(args, multiple ? objs : objs[0]); 1568 }; 1569 1570 /** 1571 * add an overlay 1572 **/ 1573 this.overlay = function(args, internal){ 1574 var id, obj, 1575 $div = $(document.createElement("div")) 1576 .css("border", "none") 1577 .css("borderWidth", "0px") 1578 .css("position", "absolute"); 1579 $div.append(args.opts.content); 1580 OverlayView.prototype = new defaults.classes.OverlayView(); 1581 obj = new OverlayView(map, args.opts, args.latLng, $div); 1582 $div = null; // memory leak 1583 if (internal){ 1584 return obj; 1585 } 1586 id = store.add(args, "overlay", obj); 1587 manageEnd(args, obj, id); 1588 }; 1589 1590 /** 1591 * returns address structure from latlng 1592 **/ 1593 this.getaddress = function(args){ 1594 callback(args, args.results, args.status); 1595 task.ack(); 1596 }; 1597 1598 /** 1599 * returns latlng from an address 1600 **/ 1601 this.getlatlng = function(args){ 1602 callback(args, args.results, args.status); 1603 task.ack(); 1604 }; 1605 1606 /** 1607 * return the max zoom of a location 1608 **/ 1609 this.getmaxzoom = function(args){ 1610 maxZoomService().getMaxZoomAtLatLng( 1611 args.latLng, 1612 function(result) { 1613 callback(args, result.status === google.maps.MaxZoomStatus.OK ? result.zoom : false, status); 1614 task.ack(); 1615 } 1616 ); 1617 }; 1618 1619 /** 1620 * return the elevation of a location 1621 **/ 1622 this.getelevation = function(args){ 1623 var i, locations = [], 1624 f = function(results, status){ 1625 callback(args, status === google.maps.ElevationStatus.OK ? results : false, status); 1626 task.ack(); 1627 }; 1628 1629 if (args.latLng){ 1630 locations.push(args.latLng); 1631 } else { 1632 locations = array(args.todo.locations || []); 1633 for(i=0; i<locations.length; i++){ 1634 locations[i] = toLatLng(locations[i]); 1635 } 1636 } 1637 if (locations.length){ 1638 elevationService().getElevationForLocations({locations:locations}, f); 1639 } else { 1640 if (args.todo.path && args.todo.path.length){ 1641 for(i=0; i<args.todo.path.length; i++){ 1642 locations.push(toLatLng(args.todo.path[i])); 1643 } 1644 } 1645 if (locations.length){ 1646 elevationService().getElevationAlongPath({path:locations, samples:args.todo.samples}, f); 1647 } else { 1648 task.ack(); 1649 } 1650 } 1651 }; 1652 1653 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 1654 => function without latLng resolution 1655 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ 1656 1657 /** 1658 * define defaults values 1659 **/ 1660 this.defaults = function(args){ 1661 $.each(args.todo, function(name, value){ 1662 if (typeof defaults[name] === "object"){ 1663 defaults[name] = $.extend({}, defaults[name], value); 1664 } else { 1665 defaults[name] = value; 1666 } 1667 }); 1668 task.ack(true); 1669 }; 1670 1671 /** 1672 * add a rectangle 1673 **/ 1674 this.rectangle = function(args){ 1675 var objs = [], multiple = "values" in args.todo; 1676 if (!multiple){ 1677 args.todo.values = [{options:args.opts}]; 1678 } 1679 if (!args.todo.values.length){ 1680 manageEnd(args, false); 1681 return; 1682 } 1683 $.each(args.todo.values, function(i, value){ 1684 var id, obj, todo = tuple(args, value); 1685 todo.options.bounds = todo.options.bounds ? toLatLngBounds(todo.options.bounds) : toLatLngBounds(value); 1686 if (!map){ 1687 newMap(todo.options.bounds.getCenter()); 1688 } 1689 todo.options.map = map; 1690 1691 obj = new defaults.classes.Rectangle(todo.options); 1692 objs.push(obj); 1693 id = store.add({todo:todo}, "rectangle", obj); 1694 attachEvents($this, {todo:todo}, obj, id); 1695 }); 1696 manageEnd(args, multiple ? objs : objs[0]); 1697 }; 1698 1699 /** 1700 * add a polygone / polyline 1701 **/ 1702 function poly(args, poly, path){ 1703 var objs = [], multiple = "values" in args.todo; 1704 if (!multiple){ 1705 args.todo.values = [{options:args.opts}]; 1706 } 1707 if (!args.todo.values.length){ 1708 manageEnd(args, false); 1709 return; 1710 } 1711 newMap(); 1712 $.each(args.todo.values, function(_, value){ 1713 var id, i, j, obj, todo = tuple(args, value); 1714 if (todo.options[path]){ 1715 if (todo.options[path][0][0] && $.isArray(todo.options[path][0][0])){ 1716 for(i=0; i<todo.options[path].length; i++){ 1717 for(j=0; j<todo.options[path][i].length; j++){ 1718 todo.options[path][i][j] = toLatLng(todo.options[path][i][j]); 1719 } 1720 } 1721 } else { 1722 for(i=0; i<todo.options[path].length; i++){ 1723 todo.options[path][i] = toLatLng(todo.options[path][i]); 1724 } 1725 } 1726 } 1727 todo.options.map = map; 1728 obj = new google.maps[poly](todo.options); 1729 objs.push(obj); 1730 id = store.add({todo:todo}, poly.toLowerCase(), obj); 1731 attachEvents($this, {todo:todo}, obj, id); 1732 }); 1733 manageEnd(args, multiple ? objs : objs[0]); 1734 } 1735 1736 this.polyline = function(args){ 1737 poly(args, "Polyline", "path"); 1738 }; 1739 1740 this.polygon = function(args){ 1741 poly(args, "Polygon", "paths"); 1742 }; 1743 1744 /** 1745 * add a traffic layer 1746 **/ 1747 this.trafficlayer = function(args){ 1748 newMap(); 1749 var obj = store.get("trafficlayer"); 1750 if (!obj){ 1751 obj = new defaults.classes.TrafficLayer(); 1752 obj.setMap(map); 1753 store.add(args, "trafficlayer", obj); 1754 } 1755 manageEnd(args, obj); 1756 }; 1757 1758 /** 1759 * add a bicycling layer 1760 **/ 1761 this.bicyclinglayer = function(args){ 1762 newMap(); 1763 var obj = store.get("bicyclinglayer"); 1764 if (!obj){ 1765 obj = new defaults.classes.BicyclingLayer(); 1766 obj.setMap(map); 1767 store.add(args, "bicyclinglayer", obj); 1768 } 1769 manageEnd(args, obj); 1770 }; 1771 1772 /** 1773 * add a ground overlay 1774 **/ 1775 this.groundoverlay = function(args){ 1776 args.opts.bounds = toLatLngBounds(args.opts.bounds); 1777 if (args.opts.bounds){ 1778 newMap(args.opts.bounds.getCenter()); 1779 } 1780 var id, obj = new defaults.classes.GroundOverlay(args.opts.url, args.opts.bounds, args.opts.opts); 1781 obj.setMap(map); 1782 id = store.add(args, "groundoverlay", obj); 1783 manageEnd(args, obj, id); 1784 }; 1785 1786 /** 1787 * set a streetview 1788 **/ 1789 this.streetviewpanorama = function(args){ 1790 if (!args.opts.opts){ 1791 args.opts.opts = {}; 1792 } 1793 if (args.latLng){ 1794 args.opts.opts.position = args.latLng; 1795 } else if (args.opts.opts.position){ 1796 args.opts.opts.position = toLatLng(args.opts.opts.position); 1797 } 1798 if (args.todo.divId){ 1799 args.opts.container = document.getElementById(args.todo.divId) 1800 } else if (args.opts.container){ 1801 args.opts.container = $(args.opts.container).get(0); 1802 } 1803 var id, obj = new defaults.classes.StreetViewPanorama(args.opts.container, args.opts.opts); 1804 if (obj){ 1805 map.setStreetView(obj); 1806 } 1807 id = store.add(args, "streetviewpanorama", obj); 1808 manageEnd(args, obj, id); 1809 }; 1810 1811 this.kmllayer = function(args){ 1812 var objs = [], multiple = "values" in args.todo; 1813 if (!multiple){ 1814 args.todo.values = [{options:args.opts}]; 1815 } 1816 if (!args.todo.values.length){ 1817 manageEnd(args, false); 1818 return; 1819 } 1820 $.each(args.todo.values, function(i, value){ 1821 var id, obj, todo = tuple(args, value); 1822 if (!map){ 1823 newMap(); 1824 } 1825 todo.options.opts.map = map; 1826 obj = new defaults.classes.KmlLayer(todo.options.url, todo.options.opts); 1827 objs.push(obj); 1828 id = store.add({todo:todo}, "kmllayer", obj); 1829 attachEvents($this, {todo:todo}, obj, id); 1830 }); 1831 manageEnd(args, multiple ? objs : objs[0]); 1832 }; 1833 1834 /** 1835 * add a fix panel 1836 **/ 1837 this.panel = function(args){ 1838 newMap(); 1839 var id, x= 0, y=0, $content, 1840 $div = $(document.createElement("div")); 1841 1842 $div 1843 .css("position", "absolute") 1844 .css("z-index", "1000"); 1845 1846 if (args.opts.content){ 1847 $content = $(args.opts.content); 1848 1849 if (args.opts.left !== undef){ 1850 x = args.opts.left; 1851 } else if (args.opts.right !== undef){ 1852 x = $this.width() - $content.width() - args.opts.right; 1853 } else if (args.opts.center){ 1854 x = ($this.width() - $content.width()) / 2; 1855 } 1856 1857 if (args.opts.top !== undef){ 1858 y = args.opts.top; 1859 } else if (args.opts.bottom !== undef){ 1860 y = $this.height() - $content.height() - args.opts.bottom; 1861 } else if (args.opts.middle){ 1862 y = ($this.height() - $content.height()) / 2 1863 } 1864 1865 $div 1866 .css("top", y+"px") 1867 .css("left", x+"px") 1868 .append($content); 1869 } 1870 1871 $this.first().prepend($div); 1872 id = store.add(args, "panel", $div); 1873 manageEnd(args, $div, id); 1874 $div = null; // memory leak 1875 }; 1876 1877 /** 1878 * Create an InternalClusterer object 1879 **/ 1880 function createClusterer(raw){ 1881 var internalClusterer = new InternalClusterer($this, map, raw.radius, raw.maxZoom), 1882 todo = {}, 1883 styles = {}, 1884 isInt = /^[0-9]+$/, 1885 calculator, 1886 k; 1887 1888 for(k in raw){ 1889 if (isInt.test(k)){ 1890 styles[k] = raw[k]; 1891 styles[k].width = styles[k].width || 0; 1892 styles[k].height = styles[k].height || 0; 1893 } else { 1894 todo[k] = raw[k]; 1895 } 1896 } 1897 1898 // external calculator 1899 if (todo.calculator){ 1900 calculator = function(indexes){ 1901 var data = []; 1902 $.each(indexes, function(i, index){ 1903 data.push(internalClusterer.value(index)); 1904 }); 1905 return todo.calculator.apply($this, [data]); 1906 }; 1907 } else { 1908 calculator = function(indexes){ 1909 return indexes.length; 1910 }; 1911 } 1912 1913 // set error function 1914 internalClusterer.error(function(){ 1915 error.apply(that, arguments); 1916 }); 1917 1918 // set display function 1919 internalClusterer.display(function(cluster){ 1920 var k, style, n = 0, atodo, obj, offset, 1921 cnt = calculator(cluster.indexes); 1922 1923 // look for the style to use 1924 if (cnt > 1){ 1925 for(k in styles){ 1926 k = 1 * k; // cast to int 1927 if (k > n && k <= cnt){ 1928 n = k; 1929 } 1930 } 1931 style = styles[n]; 1932 } 1933 1934 if (style){ 1935 offset = style.offset || [-style.width/2, -style.height/2]; 1936 // create a custom overlay command 1937 // nb: 2 extends are faster that a deeper extend 1938 atodo = $.extend({}, todo); 1939 atodo.options = $.extend({ 1940 pane: "overlayLayer", 1941 content:style.content ? style.content.replace("CLUSTER_COUNT", cnt) : "", 1942 offset:{ 1943 x: ("x" in offset ? offset.x : offset[0]) || 0, 1944 y: ("y" in offset ? offset.y : offset[1]) || 0 1945 } 1946 }, 1947 todo.options || {}); 1948 1949 obj = that.overlay({todo:atodo, opts:atodo.options, latLng:toLatLng(cluster)}, true); 1950 1951 atodo.options.pane = "floatShadow"; 1952 atodo.options.content = $(document.createElement("div")).width(style.width+"px").height(style.height+"px"); 1953 shadow = that.overlay({todo:atodo, opts:atodo.options, latLng:toLatLng(cluster)}, true); 1954 1955 // store data to the clusterer 1956 todo.data = { 1957 latLng: toLatLng(cluster), 1958 markers:[] 1959 }; 1960 $.each(cluster.indexes, function(i, index){ 1961 todo.data.markers.push(internalClusterer.value(index)); 1962 if (internalClusterer.marker(index)){ 1963 internalClusterer.marker(index).setMap(null); 1964 } 1965 }); 1966 attachEvents($this, {todo:todo}, shadow, undef, {main:obj, shadow:shadow}); 1967 internalClusterer.store(cluster, obj, shadow); 1968 } else { 1969 $.each(cluster.indexes, function(i, index){ 1970 if (internalClusterer.marker(index)){ 1971 internalClusterer.marker(index).setMap(map); 1233 1972 } else { 1234 var out = status === google.maps.GeocoderStatus.OK ? results : false; 1235 callback.apply($this, [out, status]); 1236 if (!out && _default.verbose){ 1237 alert('Geocode error : ' + status); 1238 } 1239 that._end(); 1973 var todo = internalClusterer.todo(index), 1974 marker = new defaults.classes.Marker(todo.options); 1975 internalClusterer.setMarker(index, marker); 1976 attachEvents($this, {todo:todo}, marker, todo.id); 1240 1977 } 1241 } 1242 ); 1978 }); 1979 } 1980 }); 1981 1982 return internalClusterer; 1983 } 1984 /** 1985 * add a marker 1986 **/ 1987 this.marker = function(args){ 1988 var multiple = "values" in args.todo, 1989 init = !map; 1990 if (!multiple){ 1991 args.opts.position = args.latLng || toLatLng(args.opts.position); 1992 args.todo.values = [{options:args.opts}]; 1993 } 1994 if (!args.todo.values.length){ 1995 manageEnd(args, false); 1996 return; 1997 } 1998 if (init){ 1999 newMap(); 2000 } 2001 2002 if (args.todo.cluster && !map.getBounds()){ // map not initialised => bounds not available : wait for map if clustering feature is required 2003 google.maps.event.addListenerOnce(map, "bounds_changed", function() { that.marker.apply(that, [args]); }); 2004 return; 2005 } 2006 if (args.todo.cluster){ 2007 var clusterer, internalClusterer; 2008 if (args.todo.cluster instanceof Clusterer){ 2009 clusterer = args.todo.cluster; 2010 internalClusterer = store.getById(clusterer.id(), true); 2011 } else { 2012 internalClusterer = createClusterer(args.todo.cluster); 2013 clusterer = new Clusterer(globalId(args.todo.id, true), internalClusterer); 2014 store.add(args, "clusterer", clusterer, internalClusterer); 2015 } 2016 internalClusterer.beginUpdate(); 2017 2018 $.each(args.todo.values, function(i, value){ 2019 var todo = tuple(args, value); 2020 todo.options.position = todo.options.position ? toLatLng(todo.options.position) : toLatLng(value); 2021 todo.options.map = map; 2022 if (init){ 2023 map.setCenter(todo.options.position); 2024 init = false; 2025 } 2026 internalClusterer.add(todo, value); 2027 }); 2028 2029 internalClusterer.endUpdate(); 2030 manageEnd(args, clusterer); 2031 1243 2032 } else { 1244 this._end(); 1245 } 1246 } 2033 var objs = []; 2034 $.each(args.todo.values, function(i, value){ 2035 var id, obj, todo = tuple(args, value); 2036 todo.options.position = todo.options.position ? toLatLng(todo.options.position) : toLatLng(value); 2037 todo.options.map = map; 2038 if (init){ 2039 map.setCenter(todo.options.position); 2040 init = false; 2041 } 2042 obj = new defaults.classes.Marker(todo.options); 2043 objs.push(obj); 2044 id = store.add({todo:todo}, "marker", obj); 2045 attachEvents($this, {todo:todo}, obj, id); 2046 }); 2047 manageEnd(args, multiple ? objs : objs[0]); 2048 } 2049 }; 1247 2050 1248 2051 /** 1249 2052 * return a route 1250 2053 **/ 1251 this.getroute = function(todo){ 1252 var callback = ival(todo, 'callback'), 1253 that = this; 1254 if ( (typeof(callback) === 'function') && todo.options ) { 1255 todo.options.origin = toLatLng(todo.options.origin, true); 1256 todo.options.destination = toLatLng(todo.options.destination, true); 1257 getDirectionsService().route( 1258 todo.options, 1259 function(results, status) { 1260 var out = status == google.maps.DirectionsStatus.OK ? results : false; 1261 callback.apply($this, [out, status]); 1262 that._end(); 1263 } 1264 ); 1265 } else { 1266 this._end(); 1267 } 1268 } 1269 1270 /** 1271 * return the elevation of a location 1272 **/ 1273 this.getelevation = function(todo){ 1274 var fnc, path, samples, i, 1275 locations = [], 1276 callback = ival(todo, 'callback'), 1277 latLng = ival(todo, 'latlng'), 1278 that = this; 1279 1280 if (typeof(callback) === 'function'){ 1281 fnc = function(results, status){ 1282 var out = status === google.maps.ElevationStatus.OK ? results : false; 1283 callback.apply($this, [out, status]); 1284 that._end(); 1285 }; 1286 if (latLng){ 1287 locations.push(toLatLng(latLng)); 1288 } else { 1289 locations = ival(todo, 'locations') || []; 1290 if (locations){ 1291 locations = array(locations); 1292 for(i=0; i<locations.length; i++){ 1293 locations[i] = toLatLng(locations[i]); 1294 } 1295 } 1296 } 1297 if (locations.length){ 1298 getElevationService().getElevationForLocations({locations:locations}, fnc); 1299 } else { 1300 path = ival(todo, 'path'); 1301 samples = ival(todo, 'samples'); 1302 if (path && samples){ 1303 for(i=0; i<path.length; i++){ 1304 locations.push(toLatLng(path[i])); 1305 } 1306 if (locations.length){ 1307 getElevationService().getElevationAlongPath({path:locations, samples:samples}, fnc); 1308 } 1309 } 1310 } 1311 } else { 1312 this._end(); 1313 } 1314 } 1315 1316 /** 1317 * return the distance between an origin and a destination 1318 * 1319 **/ 1320 this.getdistance = function(todo){ 1321 var i, 1322 callback = ival(todo, 'callback'), 1323 that = this; 1324 if ( (typeof(callback) === 'function') && todo.options && todo.options.origins && todo.options.destinations ) { 1325 // origins and destinations are array containing one or more address strings and/or google.maps.LatLng objects 1326 todo.options.origins = array(todo.options.origins); 1327 for(i=0; i<todo.options.origins.length; i++){ 1328 todo.options.origins[i] = toLatLng(todo.options.origins[i], true); 1329 } 1330 todo.options.destinations = array(todo.options.destinations); 1331 for(i=0; i<todo.options.destinations.length; i++){ 1332 todo.options.destinations[i] = toLatLng(todo.options.destinations[i], true); 1333 } 1334 getDistanceMatrixService().getDistanceMatrix( 1335 todo.options, 1336 function(results, status) { 1337 var out = status == google.maps.DistanceMatrixStatus.OK ? results : false; 1338 callback.apply($this, [out, status]); 1339 that._end(); 1340 } 1341 ); 1342 } else { 1343 this._end(); 1344 } 1345 } 1346 1347 /** 1348 * Add a marker to a map after address resolution 1349 * if [infowindow] add an infowindow attached to the marker 1350 **/ 1351 this.addmarker = function(todo){ 1352 this._resolveLatLng(todo, '_addMarker'); 1353 } 1354 1355 this._addMarker = function(todo, latLng, internal){ 1356 var result, oi, to, 1357 o = getObject('marker', todo, 'to'); 1358 if (!internal){ 1359 if (!latLng) { 1360 this._manageEnd(false, o); 1361 return; 1362 } 1363 this._subcall(todo, latLng); 1364 } else if (!latLng){ 1365 return; 1366 } 1367 if (o.to){ 1368 to = store.refToObj(o.to); 1369 result = to && (typeof(to.add) === 'function'); 1370 if (result){ 1371 to.add(latLng, todo); 1372 if (typeof(to.redraw) === 'function'){ 1373 to.redraw(); 1374 } 1375 } 1376 if (!internal){ 1377 this._manageEnd(result, o); 1378 } 1379 } else { 1380 o.options.position = latLng; 1381 o.options.map = map; 1382 result = new _default.classes.Marker(o.options); 1383 if (hasKey(todo, 'infowindow')){ 1384 oi = getObject('infowindow', todo['infowindow'], 'open'); 1385 // if "open" is not defined, add it in first position 1386 if ( (oi.open === undefined) || oi.open ){ 1387 oi.apply = array(oi.apply); 1388 oi.apply.unshift({action:'open', args:[map, result]}); 1389 } 1390 oi.action = 'addinfowindow'; 1391 this._planNext(oi); 1392 } 1393 if (!internal){ 1394 store.add('marker', result, o); 1395 this._manageEnd(result, o); 1396 } 1397 } 1398 return result; 1399 } 1400 1401 /** 1402 * add markers (without address resolution) 1403 **/ 1404 this.addmarkers = function(todo){ 1405 if (ival(todo, 'clusters')){ 1406 this._resolveAllLatLng(todo, 'markers', '_addclusteredmarkers'); 1407 } else { 1408 this._resolveAllLatLng(todo, 'markers', '_addmarkers'); 1409 } 1410 } 1411 1412 this._addmarkers = function(todo){ 1413 var result, o, i, latLng, marker, options = {}, tmp, to, 1414 markers = ival(todo, 'markers'); 1415 this._subcall(todo); 1416 if (typeof(markers) !== 'object') { 1417 return this._end(); 1418 } 1419 o = getObject('marker', todo, ['to', 'markers']); 1420 1421 if (o.to){ 1422 to = store.refToObj(o.to); 1423 result = to && (typeof(to.add) === 'function'); 1424 if (result){ 1425 for(i=0; i<markers.length; i++){ 1426 if (latLng = toLatLng(markers[i])) { 1427 to.add(latLng, markers[i]); 1428 } 1429 } 1430 if (typeof(to.redraw) === 'function'){ 1431 to.redraw(); 1432 } 1433 } 1434 this._manageEnd(result, o); 1435 } else { 1436 $.extend(true, options, o.options); 1437 options.map = map; 1438 result = []; 1439 for(i=0; i<markers.length; i++){ 1440 if (latLng = toLatLng(markers[i])){ 1441 if (markers[i].options){ 1442 tmp = {}; 1443 $.extend(true, tmp, options, markers[i].options); 1444 o.options = tmp; 1445 } else { 1446 o.options = options; 1447 } 1448 o.options.position = latLng; 1449 marker = new _default.classes.Marker(o.options); 1450 result.push(marker); 1451 o.data = markers[i].data; 1452 o.tag = markers[i].tag; 1453 store.add('marker', marker, o); 1454 this._manageEnd(marker, o, true); 1455 } 1456 } 1457 o.options = options; // restore previous for futur use 1458 this._callback(result, todo); 1459 this._end(); 1460 } 1461 } 1462 1463 this._addclusteredmarkers = function(todo){ 1464 var clusterer, i, latLng, storeId, 1465 that = this, 1466 radius = ival(todo, 'radius'), 1467 maxZoom = ival(todo, 'maxZoom'), 1468 markers = ival(todo, 'markers'), 1469 styles = ival(todo, 'clusters'); 1470 1471 if (!map.getBounds()){ // map not initialised => bounds not available 1472 // wait for map 1473 google.maps.event.addListenerOnce( 1474 map, 1475 'bounds_changed', 1476 function() { 1477 that._addclusteredmarkers(todo); 1478 } 1479 ); 1480 return; 1481 } 1482 1483 if (typeof(radius) === 'number'){ 1484 clusterer = new Clusterer(); 1485 for(i=0 ; i<markers.length; i++){ 1486 latLng = toLatLng(markers[i]); 1487 clusterer.add(latLng, markers[i]); 1488 } 1489 storeId = this._initClusters(todo, clusterer, radius, maxZoom, styles); 1490 } 1491 1492 this._callback(storeId, todo); 1493 this._end(); 1494 } 1495 1496 1497 this._initClusters = function(todo, clusterer, radius, maxZoom, styles){ 1498 var that = this; 1499 1500 clusterer.setRedraw(function(force){ 1501 var same, clusters = clusterer.clusters(map, radius, maxZoom, force); 1502 if (clusters){ 1503 same = clusterer.freeDiff(clusters); 1504 that._displayClusters(todo, clusterer, clusters, same, styles); 2054 this.getroute = function(args){ 2055 args.opts.origin = toLatLng(args.opts.origin, true); 2056 args.opts.destination = toLatLng(args.opts.destination, true); 2057 directionsService().route( 2058 args.opts, 2059 function(results, status) { 2060 callback(args, status == google.maps.DirectionsStatus.OK ? results : false, status); 2061 task.ack(); 2062 } 2063 ); 2064 }; 2065 2066 /** 2067 * add a direction renderer 2068 **/ 2069 this.directionsrenderer = function(args){ 2070 args.opts.map = map; 2071 var id, obj = new google.maps.DirectionsRenderer(args.opts); 2072 if (args.todo.divId){ 2073 obj.setPanel(document.getElementById(args.todo.divId)); 2074 } else if (args.todo.container){ 2075 obj.setPanel($(args.todo.container).get(0)); 2076 } 2077 id = store.add(args, "directionrenderer", obj); 2078 manageEnd(args, obj, id); 2079 }; 2080 2081 /** 2082 * returns latLng of the user 2083 **/ 2084 this.getgeoloc = function(args){ 2085 manageEnd(args, args.latLng); 2086 }; 2087 2088 /** 2089 * add a style 2090 **/ 2091 this.styledmaptype = function(args){ 2092 newMap(); 2093 var obj = new defaults.classes.StyledMapType(args.todo.styles, args.opts); 2094 map.mapTypes.set(args.todo.id, obj); 2095 manageEnd(args, obj); 2096 }; 2097 2098 /** 2099 * add an imageMapType 2100 **/ 2101 this.imagemaptype = function(args){ 2102 newMap(); 2103 var obj = new defaults.classes.ImageMapType(args.opts); 2104 map.mapTypes.set(args.todo.id, obj); 2105 manageEnd(args, obj); 2106 }; 2107 2108 /** 2109 * autofit a map using its overlays (markers, rectangles ...) 2110 **/ 2111 this.autofit = function(args){ 2112 var bounds = new google.maps.LatLngBounds(); 2113 2114 $.each(store.all(), function(i, obj){ 2115 if (obj.getPosition){ 2116 bounds.extend(obj.getPosition()); 2117 } else if (obj.getBounds){ 2118 bounds.extend(obj.getBounds().getNorthEast()); 2119 bounds.extend(obj.getBounds().getSouthWest()); 2120 } else if (obj.getPaths){ 2121 obj.getPaths().forEach(function(path){ 2122 path.forEach(function(latLng){ 2123 bounds.extend(latLng); 2124 }); 2125 }); 2126 } else if (obj.getPath){ 2127 obj.getPath().forEach(function(latLng){ 2128 bounds.extend(latLng);"" 2129 }); 2130 } else if (obj.getCenter){ 2131 bounds.extend(obj.getCenter()); 1505 2132 } 1506 2133 }); 1507 1508 clusterer.events(1509 google.maps.event.addListener(1510 map,1511 'zoom_changed',1512 function() {1513 clusterer.redraw(true);1514 }1515 ),1516 google.maps.event.addListener(1517 map,1518 'bounds_changed',1519 function() {1520 clusterer.redraw();1521 }1522 )1523 );1524 1525 clusterer.redraw();1526 return store.add('cluster', clusterer, todo);1527 }1528 1529 this._displayClusters = function(todo, clusterer, clusters, same, styles){1530 var k, i, ii, m, done, obj, shadow, cluster, options, tmp, w, h,1531 atodo,1532 ctodo = hasKey(todo, 'cluster') ? getObject('', ival(todo, 'cluster')) : {},1533 mtodo = hasKey(todo, 'marker') ? getObject('', ival(todo, 'marker')) : {};1534 for(i=0; i<clusters.length; i++){1535 if (i in same){1536 continue;1537 }1538 cluster = clusters[i];1539 done = false;1540 if (cluster.idx.length > 1){1541 // look for the cluster design to use1542 m = 0;1543 for(k in styles){1544 if ( (k > m) && (k <= cluster.idx.length) ){1545 m = k;1546 }1547 }1548 if (styles[m]){ // cluster defined for the current markers count1549 w = ival(styles[m], 'width');1550 h = ival(styles[m], 'height');1551 1552 // create a custom _addOverlay command1553 atodo = {};1554 $.extend(1555 true,1556 atodo,1557 ctodo,1558 { options:{1559 pane: 'overlayLayer',1560 content:styles[m].content.replace('CLUSTER_COUNT', cluster.idx.length),1561 offset:{1562 x: -w/2,1563 y: -h/21564 }1565 }1566 }1567 );1568 obj = this._addOverlay(atodo, toLatLng(cluster), true);1569 atodo.options.pane = 'floatShadow';1570 atodo.options.content = $('<div></div>');1571 atodo.options.content.width(w);1572 atodo.options.content.height(h);1573 shadow = this._addOverlay(atodo, toLatLng(cluster), true);1574 1575 // store data to the clusterer1576 ctodo.data = {1577 latLng: toLatLng(cluster),1578 markers:[]1579 };1580 for(ii=0; ii<cluster.idx.length; ii++){1581 ctodo.data.markers.push(1582 clusterer.get(cluster.idx[ii]).marker1583 );1584 }1585 this._attachEvents(shadow, ctodo);1586 clusterer.store(cluster, obj, shadow);1587 done = true;1588 }1589 }1590 if (!done){ // cluster not defined (< min count) or = 1 so display all markers of the current cluster1591 // save the defaults options for the markers1592 options = {};1593 $.extend(true, options, mtodo.options);1594 for(ii = 0; ii <cluster.idx.length; ii++){1595 m = clusterer.get(cluster.idx[ii]);1596 mtodo.latLng = m.latLng;1597 mtodo.data = m.marker.data;1598 mtodo.tag = m.marker.tag;1599 if (m.marker.options){1600 tmp = {};1601 $.extend(true, tmp, options, m.marker.options);1602 mtodo.options = tmp;1603 } else {1604 mtodo.options = options;1605 }1606 obj = this._addMarker(mtodo, mtodo.latLng, true);1607 this._attachEvents(obj, mtodo);1608 clusterer.store(cluster, obj);1609 }1610 mtodo.options = options; // restore previous for futur use1611 }1612 }1613 }1614 1615 /**1616 * add an infowindow after address resolution1617 **/1618 this.addinfowindow = function(todo){1619 this._resolveLatLng(todo, '_addInfoWindow');1620 }1621 1622 this._addInfoWindow = function(todo, latLng){1623 var o, infowindow, args = [];1624 this._subcall(todo, latLng);1625 o = getObject('infowindow', todo, ['open', 'anchor']);1626 if (latLng) {1627 o.options.position = latLng;1628 }1629 infowindow = new _default.classes.InfoWindow(o.options);1630 if ( (o.open === undefined) || o.open ){1631 o.apply = array(o.apply);1632 args.push(map);1633 if (o.anchor){1634 args.push(o.anchor);1635 }1636 o.apply.unshift({action:'open', args:args});1637 }1638 store.add('infowindow', infowindow, o);1639 this._manageEnd(infowindow, o);1640 }1641 1642 1643 /**1644 * add a polygone / polylin on a map1645 **/1646 this.addpolyline = function(todo){1647 this._addPoly(todo, 'Polyline', 'path');1648 }1649 1650 this.addpolygon = function(todo){1651 this._addPoly(todo, 'Polygon', 'paths');1652 }1653 1654 this._addPoly = function(todo, poly, path){1655 var i,1656 obj, latLng,1657 o = getObject(poly.toLowerCase(), todo, path);1658 if (o[path]){1659 o.options[path] = [];1660 for(i=0; i<o[path].length; i++){1661 if (latLng = toLatLng(o[path][i])){1662 o.options[path].push(latLng);1663 }1664 }1665 }1666 obj = new google.maps[poly](o.options);1667 obj.setMap(map);1668 store.add(poly.toLowerCase(), obj, o);1669 this._manageEnd(obj, o);1670 }1671 1672 /**1673 * add a circle1674 **/1675 this.addcircle = function(todo){1676 this._resolveLatLng(todo, '_addCircle');1677 }1678 1679 this._addCircle = function(todo, latLng){1680 var c, o = getObject('circle', todo);1681 if (!latLng) {1682 latLng = toLatLng(o.options.center);1683 }1684 if (!latLng) {1685 return this._manageEnd(false, o);1686 }1687 this._subcall(todo, latLng);1688 o.options.center = latLng;1689 o.options.map = map;1690 c = new _default.classes.Circle(o.options);1691 store.add('circle', c, o);1692 this._manageEnd(c, o);1693 }1694 1695 /**1696 * add a rectangle1697 **/1698 this.addrectangle = function(todo){1699 this._resolveLatLng(todo, '_addRectangle');1700 }1701 1702 this._addRectangle = function(todo, latLng ){1703 var r, o = getObject('rectangle', todo);1704 o.options.bounds = toLatLngBounds(o.options.bounds, true);1705 if (!o.options.bounds) {1706 return this._manageEnd(false, o);1707 }1708 this._subcall(todo, o.options.bounds.getCenter());1709 o.options.map = map;1710 r = new _default.classes.Rectangle(o.options);1711 store.add('rectangle', r, o);1712 this._manageEnd(r, o);1713 }1714 1715 /**1716 * add an overlay to a map after address resolution1717 **/1718 this.addoverlay = function(todo){1719 this._resolveLatLng(todo, '_addOverlay');1720 }1721 1722 this._addOverlay = function(todo, latLng, internal){1723 var ov,1724 o = getObject('overlay', todo),1725 opts = $.extend({1726 pane: 'floatPane',1727 content: '',1728 offset:{1729 x:0,y:01730 }1731 },1732 o.options),1733 $div = $('<div></div>'),1734 listeners = [];1735 1736 $div1737 .css('border', 'none')1738 .css('borderWidth', '0px')1739 .css('position', 'absolute');1740 $div.append(opts.content);1741 1742 function f() {1743 _default.classes.OverlayView.call(this);1744 this.setMap(map);1745 }1746 1747 f.prototype = new _default.classes.OverlayView();1748 1749 f.prototype.onAdd = function() {1750 var panes = this.getPanes();1751 if (opts.pane in panes) {1752 $(panes[opts.pane]).append($div);1753 }1754 }1755 f.prototype.draw = function() {1756 var overlayProjection = this.getProjection(),1757 ps = overlayProjection.fromLatLngToDivPixel(latLng),1758 that = this;1759 1760 $div1761 .css('left', (ps.x+opts.offset.x) + 'px')1762 .css('top' , (ps.y+opts.offset.y) + 'px');1763 1764 $.each( ("dblclick click mouseover mousemove mouseout mouseup mousedown").split(" "), function( i, name ) {1765 listeners.push(1766 google.maps.event.addDomListener($div[0], name, function(e) {1767 google.maps.event.trigger(that, name);1768 })1769 );1770 });1771 listeners.push(1772 google.maps.event.addDomListener($div[0], "contextmenu", function(e) {1773 google.maps.event.trigger(that, "rightclick");1774 })1775 );1776 }1777 f.prototype.onRemove = function() {1778 for (var i = 0; i < listeners.length; i++) {1779 google.maps.event.removeListener(listeners[i]);1780 }1781 $div.remove();1782 }1783 f.prototype.hide = function() {1784 $div.hide();1785 }1786 f.prototype.show = function() {1787 $div.show();1788 }1789 f.prototype.toggle = function() {1790 if ($div) {1791 if ($div.is(':visible')){1792 this.show();1793 } else {1794 this.hide();1795 }1796 }1797 }1798 f.prototype.toggleDOM = function() {1799 if (this.getMap()) {1800 this.setMap(null);1801 } else {1802 this.setMap(map);1803 }1804 }1805 f.prototype.getDOMElement = function() {1806 return $div[0];1807 }1808 ov = new f();1809 if (!internal){1810 store.add('overlay', ov, o);1811 this._manageEnd(ov, o);1812 }1813 return ov;1814 }1815 1816 /**1817 * add a fix panel to a map1818 **/1819 this.addfixpanel = function(todo){1820 var o = getObject('fixpanel', todo),1821 x=y=0, $c, $div;1822 if (o.options.content){1823 $c = $(o.options.content);1824 1825 if (o.options.left !== undefined){1826 x = o.options.left;1827 } else if (o.options.right !== undefined){1828 x = $this.width() - $c.width() - o.options.right;1829 } else if (o.options.center){1830 x = ($this.width() - $c.width()) / 2;1831 }1832 1833 if (o.options.top !== undefined){1834 y = o.options.top;1835 } else if (o.options.bottom !== undefined){1836 y = $this.height() - $c.height() - o.options.bottom;1837 } else if (o.options.middle){1838 y = ($this.height() - $c.height()) / 21839 }1840 1841 $div = $('<div></div>')1842 .css('position', 'absolute')1843 .css('top', y+'px')1844 .css('left', x+'px')1845 .css('z-index', '1000')1846 .append($c);1847 1848 $this.first().prepend($div);1849 this._attachEvents(map, o);1850 store.add('fixpanel', $div, o);1851 this._callback($div, o);1852 }1853 this._end();1854 }1855 1856 /**1857 * add a direction renderer to a map1858 **/1859 this.adddirectionsrenderer = function(todo, internal){1860 var dr, o = getObject('directionrenderer', todo, 'panelId');1861 o.options.map = map;1862 dr = new google.maps.DirectionsRenderer(o.options);1863 if (o.panelId) {1864 dr.setPanel(document.getElementById(o.panelId));1865 }1866 store.add('directionrenderer', dr, o);1867 this._manageEnd(dr, o, internal);1868 return dr;1869 }1870 1871 /**1872 * set a direction panel to a dom element from its ID1873 **/1874 this.setdirectionspanel = function(todo){1875 var dr = store.get('directionrenderer'),1876 o = getObject('directionpanel', todo, 'id');1877 if (dr && o.id) {1878 dr.setPanel(document.getElementById(o.id));1879 }1880 this._manageEnd(dr, o);1881 }1882 1883 /**1884 * set directions on a map (create Direction Renderer if needed)1885 **/1886 this.setdirections = function(todo){1887 var dr = store.get('directionrenderer'),1888 o = getObject('directions', todo);1889 if (todo) {1890 o.options.directions = todo.directions ? todo.directions : (todo.options && todo.options.directions ? todo.options.directions : null);1891 }1892 if (o.options.directions) {1893 if (!dr) {1894 dr = this.adddirectionsrenderer(o, true);1895 } else {1896 dr.setDirections(o.options.directions);1897 }1898 }1899 this._manageEnd(dr, o);1900 }1901 1902 /**1903 * set a streetview to a map1904 **/1905 this.setstreetview = function(todo){1906 var panorama,1907 o = getObject('streetview', todo, 'id');1908 if (o.options.position){1909 o.options.position = toLatLng(o.options.position);1910 }1911 panorama = new _default.classes.StreetViewPanorama(document.getElementById(o.id),o.options);1912 if (panorama){1913 map.setStreetView(panorama);1914 }1915 this._manageEnd(panorama, o);1916 }1917 1918 /**1919 * add a kml layer to a map1920 **/1921 this.addkmllayer = function(todo){1922 var kml,1923 o = getObject('kmllayer', todo, 'url');1924 o.options.map = map;1925 if (typeof(o.url) === 'string'){1926 kml = new _default.classes.KmlLayer(o.url, o.options);1927 }1928 store.add('kmllayer', kml, o);1929 this._manageEnd(kml, o);1930 }1931 1932 /**1933 * add a traffic layer to a map1934 **/1935 this.addtrafficlayer = function(todo){1936 var o = getObject('trafficlayer', todo),1937 tl = store.get('trafficlayer');1938 if (!tl){1939 tl = new _default.classes.TrafficLayer();1940 tl.setMap(map);1941 store.add('trafficlayer', tl, o);1942 }1943 this._manageEnd(tl, o);1944 }1945 1946 /**1947 * add a bicycling layer to a map1948 **/1949 this.addbicyclinglayer = function(todo){1950 var o = getObject('bicyclinglayer', todo),1951 bl = store.get('bicyclinglayer');1952 if (!bl){1953 bl = new _default.classes.BicyclingLayer();1954 bl.setMap(map);1955 store.add('bicyclinglayer', bl, o);1956 }1957 this._manageEnd(bl, o);1958 }1959 1960 /**1961 * add a ground overlay to a map1962 **/1963 this.addgroundoverlay = function(todo){1964 var ov,1965 o = getObject('groundoverlay', todo, ['bounds', 'url']);1966 o.bounds = toLatLngBounds(o.bounds);1967 if (o.bounds && (typeof(o.url) === 'string')){1968 ov = new _default.classes.GroundOverlay(o.url, o.bounds);1969 ov.setMap(map);1970 store.add('groundoverlay', ov, o);1971 }1972 this._manageEnd(ov, o);1973 }1974 1975 /**1976 * geolocalise the user and return a LatLng1977 **/1978 this.geolatlng = function(todo){1979 var callback = ival(todo, 'callback');1980 if (typeof(callback) === 'function') {1981 if(navigator.geolocation) {1982 navigator.geolocation.getCurrentPosition(1983 function(position) {1984 var out = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);1985 callback.apply($this, [out]);1986 },1987 function() {1988 var out = false;1989 callback.apply($this, [out]);1990 }1991 );1992 } else if (google.gears) {1993 google.gears.factory.create('beta.geolocation').getCurrentPosition(1994 function(position) {1995 var out = new google.maps.LatLng(position.latitude,position.longitude);1996 callback.apply($this, [out]);1997 },1998 function() {1999 out = false;2000 callback.apply($this, [out]);2001 }2002 );2003 } else {2004 callback.apply($this, [false]);2005 }2006 }2007 this._end();2008 }2009 2010 /**2011 * add a style to a map2012 **/2013 this.addstyledmap = function(todo, internal){2014 var o = getObject('styledmap', todo, ['id', 'style']);2015 if (o.style && o.id && !styles[o.id]) {2016 styles[o.id] = new _default.classes.StyledMapType(o.style, o.options);2017 if (map) {2018 map.mapTypes.set(o.id, styles[o.id]);2019 }2020 }2021 this._manageEnd(styles[o.id], o, internal);2022 }2023 2024 /**2025 * set a style to a map (add it if needed)2026 **/2027 this.setstyledmap = function(todo){2028 var o = getObject('styledmap', todo, ['id', 'style']);2029 if (o.id) {2030 this.addstyledmap(o, true);2031 if (styles[o.id]) {2032 map.setMapTypeId(o.id);2033 this._callback(styles[o.id], todo);2034 }2035 }2036 this._manageEnd(styles[o.id], o);2037 }2038 2039 /**2040 * remove objects from a map2041 **/2042 this.clear = function(todo){2043 var list = array(ival(todo, 'list') || ival(todo, 'name')),2044 last = ival(todo, 'last', false),2045 first = ival(todo, 'first', false),2046 tag = ival(todo, 'tag');2047 if (tag !== undefined){2048 tag = array(tag);2049 }2050 store.clear(list, last, first, tag);2051 this._end();2052 }2053 2054 /**2055 * return objects previously created2056 **/2057 this.get = function(todo){2058 var name = ival(todo, 'name') || 'map',2059 first= ival(todo, 'first'),2060 all = ival(todo, 'all'),2061 tag = ival(todo, 'tag');2062 name = name.toLowerCase();2063 if (name === 'map'){2064 return map;2065 }2066 if (tag !== undefined){2067 tag = array(tag);2068 }2069 if (first){2070 return store.get(name, false, tag);2071 } else if (all){2072 return store.all(name, tag);2073 } else {2074 return store.get(name, true, tag);2075 }2076 }2077 2078 /**2079 * return the max zoom of a location2080 **/2081 this.getmaxzoom = function(todo){2082 this._resolveLatLng(todo, '_getMaxZoom');2083 }2084 2085 this._getMaxZoom = function(todo, latLng){2086 var callback = ival(todo, 'callback'),2087 that = this;2088 if (callback && typeof(callback) === 'function') {2089 getMaxZoomService().getMaxZoomAtLatLng(2090 latLng,2091 function(result) {2092 var zoom = result.status === google.maps.MaxZoomStatus.OK ? result.zoom : false;2093 callback.apply($this, [zoom, result.status]);2094 that._end();2095 }2096 );2097 } else {2098 this._end();2099 }2100 }2101 2102 /**2103 * modify default values2104 **/2105 this.setdefault = function(todo){2106 setDefault(todo);2107 this._end();2108 }2109 2110 /**2111 * autofit a map using its overlays (markers, rectangles ...)2112 **/2113 this.autofit = function(todo, internal){2114 var names, list, obj, i, j,2115 empty = true,2116 bounds = new google.maps.LatLngBounds(),2117 maxZoom = ival(todo, 'maxZoom', null);2118 2134 2119 names = store.names(); 2120 for(i=0; i<names.length; i++){ 2121 list = store.all(names[i]); 2122 for(j=0; j<list.length; j++){ 2123 obj = list[j]; 2124 if (obj.getPosition){ 2125 bounds.extend(obj.getPosition()); 2126 empty = false; 2127 } else if (obj.getBounds){ 2128 bounds.extend(obj.getBounds().getNorthEast()); 2129 bounds.extend(obj.getBounds().getSouthWest()); 2130 empty = false; 2131 } else if (obj.getPaths){ 2132 obj.getPaths().forEach(function(path){ 2133 path.forEach(function(latLng){ 2134 bounds.extend(latLng); 2135 empty = false; 2136 }); 2137 }); 2138 } else if (obj.getPath){ 2139 obj.getPath().forEach(function(latLng){ 2140 bounds.extend(latLng); 2141 empty = false; 2142 }); 2143 } else if (obj.getCenter){ 2144 bounds.extend(obj.getCenter()); 2145 empty = false; 2146 } 2147 } 2148 } 2149 2150 if (!empty && (!map.getBounds() || !map.getBounds().equals(bounds))){ 2151 if (maxZoom !== null){ 2135 if (!bounds.isEmpty() && (!map.getBounds() || !map.getBounds().equals(bounds))){ 2136 if ("maxZoom" in args.todo){ 2152 2137 // fitBouds Callback event => detect zoom level and check maxZoom 2153 2138 google.maps.event.addListenerOnce( 2154 2139 map, 2155 'bounds_changed',2140 "bounds_changed", 2156 2141 function() { 2157 if (this.getZoom() > maxZoom){2158 this.setZoom( maxZoom);2142 if (this.getZoom() > args.todo.maxZoom){ 2143 this.setZoom(args.todo.maxZoom); 2159 2144 } 2160 2145 } … … 2163 2148 map.fitBounds(bounds); 2164 2149 } 2165 if (!internal){ 2166 this._manageEnd(empty ? false : bounds, todo, internal); 2167 } 2168 } 2169 2170 }; 2150 manageEnd(args, true); 2151 }; 2152 2153 /** 2154 * remove objects from a map 2155 **/ 2156 this.clear = function(args){ 2157 if (typeof args.todo === "string"){ 2158 if (store.clearById(args.todo) || store.objClearById(args.todo)){ 2159 manageEnd(args, true); 2160 return; 2161 } 2162 args.todo = {name:args.todo}; 2163 } 2164 if (args.todo.id){ 2165 $.each(array(args.todo.id), function(i, id){ 2166 store.clearById(id); 2167 }); 2168 } else { 2169 store.clear(array(args.todo.name), args.todo.last, args.todo.first, args.todo.tag); 2170 } 2171 manageEnd(args, true); 2172 }; 2173 2174 /** 2175 * run a function on each items selected 2176 **/ 2177 this.exec = function(args){ 2178 var that = this; 2179 $.each(array(args.todo.func), function(i, func){ 2180 $.each(that.get(args.todo, true, args.todo.hasOwnProperty("full") ? args.todo.full : true), function(j, res){ 2181 func.call($this, res); 2182 }); 2183 }); 2184 manageEnd(args, true); 2185 }; 2186 2187 /** 2188 * return objects previously created 2189 **/ 2190 this.get = function(args, direct, full){ 2191 var name, res, 2192 todo = direct ? args : args.todo; 2193 if (!direct) { 2194 full = todo.full; 2195 } 2196 if (typeof todo === "string"){ 2197 res = store.getById(todo, false, full) || store.objGetById(todo); 2198 if (res === false){ 2199 name = todo; 2200 todo = {}; 2201 } 2202 } else { 2203 name = todo.name; 2204 } 2205 if (name === "map"){ 2206 res = map; 2207 } 2208 if (!res){ 2209 res = []; 2210 if (todo.id){ 2211 $.each(array(todo.id), function(i, id) { 2212 res.push(store.getById(id, false, full) || store.objGetById(id)); 2213 }); 2214 if (!$.isArray(todo.id)) { 2215 res = res[0]; 2216 } 2217 } else { 2218 $.each(name ? array(name) : [undef], function(i, aName) { 2219 var result; 2220 if (todo.first){ 2221 result = store.get(aName, false, todo.tag, full); 2222 if (result) res.push(result); 2223 } else if (todo.all){ 2224 $.each(store.all(aName, todo.tag, full), function(i, result){ 2225 res.push(result); 2226 }); 2227 } else { 2228 result = store.get(aName, true, todo.tag, full); 2229 if (result) res.push(result); 2230 } 2231 }); 2232 if (!todo.all && !$.isArray(name)) { 2233 res = res[0]; 2234 } 2235 } 2236 } 2237 res = $.isArray(res) || !todo.all ? res : [res]; 2238 if (direct){ 2239 return res; 2240 } else { 2241 manageEnd(args, res); 2242 } 2243 }; 2244 2245 /** 2246 * return the distance between an origin and a destination 2247 * 2248 **/ 2249 this.getdistance = function(args){ 2250 var i; 2251 args.opts.origins = array(args.opts.origins); 2252 for(i=0; i<args.opts.origins.length; i++){ 2253 args.opts.origins[i] = toLatLng(args.opts.origins[i], true); 2254 } 2255 args.opts.destinations = array(args.opts.destinations); 2256 for(i=0; i<args.opts.destinations.length; i++){ 2257 args.opts.destinations[i] = toLatLng(args.opts.destinations[i], true); 2258 } 2259 distanceMatrixService().getDistanceMatrix( 2260 args.opts, 2261 function(results, status) { 2262 callback(args, status === google.maps.DistanceMatrixStatus.OK ? results : false, status); 2263 task.ack(); 2264 } 2265 ); 2266 }; 2267 2268 /** 2269 * trigger events on the map 2270 **/ 2271 this.trigger = function(args){ 2272 if (typeof args.todo === "string"){ 2273 google.maps.event.trigger(map, args.todo); 2274 } else { 2275 var options = [map, args.todo.eventName]; 2276 if (args.todo.var_args) { 2277 $.each(args.todo.var_args, function(i, v){ 2278 options.push(v); 2279 }); 2280 } 2281 google.maps.event.trigger.apply(google.maps.event, options); 2282 } 2283 callback(args); 2284 task.ack(); 2285 }; 2286 } 2287 2288 /** 2289 * Return true if get is a direct call 2290 * it means : 2291 * - get is the only key 2292 * - get has no callback 2293 * @param obj {Object} The request to check 2294 * @return {Boolean} 2295 */ 2296 function isDirectGet(obj) { 2297 var k; 2298 if (!typeof obj === "object" || !obj.hasOwnProperty("get")){ 2299 return false; 2300 } 2301 for(k in obj) { 2302 if (k !== "get") { 2303 return false; 2304 } 2305 } 2306 return !obj.get.hasOwnProperty("callback"); 2307 } 2171 2308 2172 2309 //-----------------------------------------------------------------------// … … 2175 2312 2176 2313 $.fn.gmap3 = function(){ 2177 var i, args, list = [], empty = true, results = []; 2314 var i, list = [], empty = true, results = []; 2315 2316 // init library 2317 initDefaults(); 2318 2178 2319 // store all arguments in a todo list 2179 2320 for(i=0; i<arguments.length; i++){ 2180 args = arguments[i] || {}; 2181 // resolve string todo - action without parameters can be simplified as string 2182 if (typeof(args) === 'string'){ 2183 args = {action:args}; 2184 } 2185 list.push(args); 2186 } 2321 if (arguments[i]){ 2322 list.push(arguments[i]); 2323 } 2324 } 2325 2187 2326 // resolve empty call - run init 2188 2327 if (!list.length) { 2189 list.push({}); 2190 } 2328 list.push("map"); 2329 } 2330 2191 2331 // loop on each jQuery object 2192 2332 $.each(this, function() { 2193 var $this = $(this), 2194 gmap3 = $this.data('gmap3'); 2333 var $this = $(this), gmap3 = $this.data("gmap3"); 2195 2334 empty = false; 2196 2335 if (!gmap3){ 2197 2336 gmap3 = new Gmap3($this); 2198 $this.data('gmap3', gmap3); 2199 } 2200 // direct call : bypass jQuery method (not stackable, return mixed) 2201 if ( (list.length == 1) && (isDirect(list[0])) ){ 2202 results.push(gmap3._direct(list[0])); 2337 $this.data("gmap3", gmap3); 2338 } 2339 if (list.length === 1 && (list[0] === "get" || isDirectGet(list[0]))){ 2340 results.push(gmap3.get(list[0] === "get" ? "map" : list[0].get, true)); 2203 2341 } else { 2204 2342 gmap3._plan(list); 2205 2343 } 2206 2344 }); 2207 // return for direct call (only) 2345 2346 // return for direct call only 2208 2347 if (results.length){ 2209 2348 if (results.length === 1){ // 1 css selector … … 2213 2352 } 2214 2353 } 2215 // manage setDefault call 2216 if (empty && (arguments.length == 2) && (typeof(arguments[0]) === 'string') && (arguments[0].toLowerCase() === 'setdefault')){ 2217 setDefault(arguments[1]); 2218 } 2354 2219 2355 return this; 2220 2356 } 2221 2357 2222 } (jQuery));2358 })(jQuery); -
lazyest-maps/trunk/js/gmap3.min.js
r564181 r695801 1 /* 1 /*! 2 2 * GMAP3 Plugin for JQuery 3 * Version : 4.14 * Date : 201 1-11-183 * Version : 5.0b 4 * Date : 2012-11-17 5 5 * Licence : GPL v3 : http://www.gnu.org/licenses/gpl.html 6 6 * Author : DEMONTE Jean-Baptiste 7 7 * Contact : jbdemonte@gmail.com 8 8 * Web site : http://gmap3.net 9 *10 * Copyright (c) 2010-2011 Jean-Baptiste DEMONTE11 * All rights reserved.12 *13 * Redistribution and use in source and binary forms, with or without14 * modification, are permitted provided that the following conditions are met:15 *16 * - Redistributions of source code must retain the above copyright17 * notice, this list of conditions and the following disclaimer.18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials provided21 * with the distribution.22 * - Neither the name of the author nor the names of its contributors23 * may be used to endorse or promote products derived from this24 * software without specific prior written permission.25 *26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE36 * POSSIBILITY OF SUCH DAMAGE.37 9 */ 38 39 (function(c){function q(){var D=[];this.empty=function(){for(var E=0;E<D.length;E++){if(D[E]){return false}}return true};this.add=function(E){D.push(E)};this.addNext=function(F){var H=[],G,E=0;for(G=0;G<D.length;G++){if(!D[G]){continue}if(E==1){H.push(F)}H.push(D[G]);E++}if(E<2){H.push(F)}D=H};this.get=function(){for(var E=0;E<D.length;E++){if(D[E]){return D[E]}}return false};this.ack=function(){for(var E=0;E<D.length;E++){if(D[E]){delete D[E];break}}if(this.empty()){D=[]}}}function o(){var D={};this.add=function(F,G,E){F=F.toLowerCase();if(!D[F]){D[F]=[]}D[F].push({obj:G,tag:s(E,"tag")});return F+"-"+(D[F].length-1)};this.get=function(G,I,F){var H,E,J;G=G.toLowerCase();if(!D[G]||!D[G].length){return null}E=I?D[G].length:-1;J=I?-1:1;for(H=0;H<D[G].length;H++){E+=J;if(D[G][E]){if(F!==undefined){if((D[G][E].tag===undefined)||(c.inArray(D[G][E].tag,F)<0)){continue}}return D[G][E].obj}}return null};this.all=function(G,F){var H,E=[];G=G.toLowerCase();if(!D[G]||!D[G].length){return E}for(H=0;H<D[G].length;H++){if(!D[G][H]){continue}if((F!==undefined)&&((D[G][H].tag===undefined)||(c.inArray(D[G][H].tag,F)<0))){continue}E.push(D[G][H].obj)}return E};this.names=function(){var F,E=[];for(F in D){E.push(F)}return E};this.refToObj=function(E){E=E.split("-");if((E.length==2)&&D[E[0]]&&D[E[0]][E[1]]){return D[E[0]][E[1]].obj}return null};this.rm=function(H,F,G){var E,J,I;H=H.toLowerCase();if(!D[H]){return false}if(F!==undefined){if(G){for(E=D[H].length-1;E>=0;E--){if((D[H][E]!==undefined)&&(D[H][E].tag!==undefined)&&(c.inArray(D[H][E].tag,F)>=0)){break}}}else{for(E=0;E<D[H].length;E++){if((D[H][E]!==undefined)&&(D[H][E].tag!==undefined)&&(c.inArray(D[H][E].tag,F)>=0)){break}}}}else{E=G?D[H].length-1:0}if(!(E in D[H])){return false}if(typeof(D[H][E].obj.setMap)==="function"){D[H][E].obj.setMap(null)}if(typeof(D[H][E].obj.remove)==="function"){D[H][E].obj.remove()}if(typeof(D[H][E].obj.free)==="function"){D[H][E].obj.free()}delete D[H][E].obj;if(F!==undefined){I=[];for(J=0;J<D[H].length;J++){if(J!==E){I.push(D[H][J])}}D[H]=I}else{if(G){D[H].pop()}else{D[H].shift()}}return true};this.clear=function(J,I,K,E){var F,H,G;if(!J||!J.length){J=[];for(F in D){J.push(F)}}else{J=g(J)}for(H=0;H<J.length;H++){if(J[H]){G=J[H].toLowerCase();if(!D[G]){continue}if(I){this.rm(G,E,true)}else{if(K){this.rm(G,E,false)}else{while(this.rm(G,E,false)){}}}}}}}function z(){var H=[],E=[],F=[],D=[],G=false,I;this.events=function(){for(var J=0;J<arguments.length;J++){E.push(arguments[J])}};this.startRedraw=function(){if(!G){G=true;return true}return false};this.endRedraw=function(){G=false};this.redraw=function(){var K,J=[],L=this;for(K=0;K<arguments.length;K++){J.push(arguments[K])}if(this.startRedraw){I.apply(L,J);this.endRedraw()}else{setTimeout(function(){L.redraw.apply(L,J)},50)}};this.setRedraw=function(J){I=J};this.store=function(J,K,L){F.push({data:J,obj:K,shadow:L})};this.free=function(){for(var J=0;J<E.length;J++){google.maps.event.removeListener(E[J])}E=[];this.freeAll()};this.freeIndex=function(J){if(typeof(F[J].obj.setMap)==="function"){F[J].obj.setMap(null)}if(typeof(F[J].obj.remove)==="function"){F[J].obj.remove()}if(F[J].shadow){if(typeof(F[J].shadow.remove)==="function"){F[J].obj.remove()}if(typeof(F[J].shadow.setMap)==="function"){F[J].shadow.setMap(null)}delete F[J].shadow}delete F[J].obj;delete F[J].data;delete F[J]};this.freeAll=function(){var J;for(J=0;J<F.length;J++){if(F[J]){this.freeIndex(J)}}F=[]};this.freeDiff=function(M){var L,K,N={},J=[];for(L=0;L<M.length;L++){J.push(M[L].idx.join("-"))}for(L=0;L<F.length;L++){if(!F[L]){continue}K=c.inArray(F[L].data.idx.join("-"),J);if(K>=0){N[K]=true}else{this.freeIndex(L)}}return N};this.add=function(K,J){H.push({latLng:K,marker:J})};this.get=function(J){return H[J]};this.clusters=function(ai,L,W,K){var M=ai.getProjection(),Y=M.fromLatLngToPoint(new google.maps.LatLng(ai.getBounds().getNorthEast().lat(),ai.getBounds().getSouthWest().lng())),ae,ad,J,X,U,T,aa,R,S=ai.getZoom(),O={},ah={},ac={},Q=[],af,ag,N,ak,V,ab,P=ai.getBounds(),Z=W&&(W<=ai.getZoom()),aj=ai.getZoom()>2;ab=0;V={};for(ae=0;ae<H.length;ae++){if(aj&&!P.contains(H[ae].latLng)){continue}X=M.fromLatLngToPoint(H[ae].latLng);O[ae]=[Math.floor((X.x-Y.x)*Math.pow(2,S)),Math.floor((X.y-Y.y)*Math.pow(2,S))];V[ae]=true;ab++}if(!K&&!Z){for(aa=0;aa<D.length;aa++){if(aa in V){ab--}else{break}}if(!ab){return false}}D=V;V=[];for(ae in O){U=O[ae][0];T=O[ae][1];if(!(U in ah)){ah[U]={}}if(!(T in ah[U])){ah[U][T]=ae;ac[ae]={};V.push(ae)}ac[ah[U][T]][ae]=true}L=Math.pow(L,2);delete (ah);aa=0;while(1){while((aa<V.length)&&!(V[aa] in ac)){aa++}if(aa==V.length){break}ae=V[aa];N=O[ae][0];ak=O[ae][1];ah=null;if(Z){ah={lat:N,lng:ak,idx:[ae]}}else{do{af={lat:0,lng:0,idx:[]};for(R=aa;R<V.length;R++){if(!(V[R] in ac)){continue}ad=V[R];if(Math.pow(N-O[ad][0],2)+Math.pow(ak-O[ad][1],2)<=L){for(J in ac[ad]){af.lat+=H[J].latLng.lat();af.lng+=H[J].latLng.lng();af.idx.push(J)}}}af.lat/=af.idx.length;af.lng/=af.idx.length;if(!ah){ag=af.idx.length>1;ah=af}else{ag=af.idx.length>ah.idx.length;if(ag){ah=af}}if(ag){X=M.fromLatLngToPoint(new google.maps.LatLng(ah.lat,ah.lng));N=Math.floor((X.x-Y.x)*Math.pow(2,S));ak=Math.floor((X.y-Y.y)*Math.pow(2,S))}}while(ag)}for(R=0;R<ah.idx.length;R++){if(ah.idx[R] in ac){delete (ac[ah.idx[R]])}}Q.push(ah)}return Q};this.getBounds=function(){var J,K=new google.maps.LatLngBounds();for(J=0;J<H.length;J++){K.extend(H[J].latLng)}return K}}var e={verbose:false,queryLimit:{attempt:5,delay:250,random:250},init:{mapTypeId:google.maps.MapTypeId.ROADMAP,center:[46.578498,2.457275],zoom:2},classes:{Map:google.maps.Map,Marker:google.maps.Marker,InfoWindow:google.maps.InfoWindow,Circle:google.maps.Circle,Rectangle:google.maps.Rectangle,OverlayView:google.maps.OverlayView,StreetViewPanorama:google.maps.StreetViewPanorama,KmlLayer:google.maps.KmlLayer,TrafficLayer:google.maps.TrafficLayer,BicyclingLayer:google.maps.BicyclingLayer,GroundOverlay:google.maps.GroundOverlay,StyledMapType:google.maps.StyledMapType}},v=["events","onces","options","apply","callback","data","tag"],i=["init","geolatlng","getlatlng","getroute","getelevation","getdistance","addstyledmap","setdefault","destroy"],p=["get"],m=directionsService=elevationService=maxZoomService=distanceMatrixService=null;function B(E){for(var D in E){if(typeof(e[D])==="object"){e[D]=c.extend({},e[D],E[D])}else{e[D]=E[D]}}}function u(E){if(!E){return true}for(var D=0;D<i.length;D++){if(i[D]===E){return false}}return true}function n(D){var F=s(D,"action");for(var E=0;E<p.length;E++){if(p[E]===F){return true}}return false}function t(E,F){if(F.toLowerCase){F=F.toLowerCase();for(var D in E){if(D.toLowerCase&&(D.toLowerCase()==F)){return D}}}return false}function s(E,F,G){var D=t(E,F);return D?E[D]:G}function C(E,F){var G,D;if(!E||!F){return false}F=g(F);for(G in E){if(G.toLowerCase){G=G.toLowerCase();for(D in F){if(G==F[D]){return true}}}}return false}function h(F,E,D){if(C(F,v)||C(F,E)){var H,G;for(H=0;H<v.length;H++){G=t(F,v[H]);D[v[H]]=G?F[G]:{}}if(E&&E.length){for(H=0;H<E.length;H++){if(G=t(F,E[H])){D[E[H]]=F[G]}}}return D}else{D.options={};for(G in F){if(G!=="action"){D.options[G]=F[G]}}return D}}function A(H,F,E,G){var K=t(F,H),I,D={},J=["map"];D.callback=s(F,"callback");E=g(E);G=g(G);if(K){return h(F[K],E,D)}if(G&&G.length){for(I=0;I<G.length;I++){J.push(G[I])}}if(!C(F,J)){D=h(F,E,D)}for(I=0;I<v.length;I++){if(v[I] in D){continue}D[v[I]]={}}return D}function l(){if(!m){m=new google.maps.Geocoder()}return m}function a(){if(!directionsService){directionsService=new google.maps.DirectionsService()}return directionsService}function r(){if(!elevationService){elevationService=new google.maps.ElevationService()}return elevationService}function x(){if(!maxZoomService){maxZoomService=new google.maps.MaxZoomService()}return maxZoomService}function b(){if(!distanceMatrixService){distanceMatrixService=new google.maps.DistanceMatrixService()}return distanceMatrixService}function d(D){return(typeof(D)==="number"||typeof(D)==="string")&&D!==""&&!isNaN(D)}function g(F){var E,D=[];if(F!==undefined){if(typeof(F)==="object"){if(typeof(F.length)==="number"){D=F}else{for(E in F){D.push(F[E])}}}else{D.push(F)}}return D}function f(E,G,D){var F=G?E:null;if(!E||(typeof(E)==="string")){return F}if(E.latLng){return f(E.latLng)}if(typeof(E.lat)==="function"){return E}else{if(d(E.lat)){return new google.maps.LatLng(E.lat,E.lng)}else{if(!D&&E.length){if(!d(E[0])||!d(E[1])){return F}return new google.maps.LatLng(E[0],E[1])}}}return F}function j(E,F,I){var H,D,G;if(!E){return null}G=I?E:null;if(typeof(E.getCenter)==="function"){return E}if(E.length){if(E.length==2){H=f(E[0]);D=f(E[1])}else{if(E.length==4){H=f([E[0],E[1]]);D=f([E[2],E[3]])}}}else{if(("ne" in E)&&("sw" in E)){H=f(E.ne);D=f(E.sw)}else{if(("n" in E)&&("e" in E)&&("s" in E)&&("w" in E)){H=f([E.n,E.e]);D=f([E.s,E.w])}}}if(H&&D){return new google.maps.LatLngBounds(D,H)}return G}function w(I){var D=new q(),F=new o(),H=null,G={},E=false;this._plan=function(K){for(var J=0;J<K.length;J++){D.add(K[J])}this._run()};this._planNext=function(J){D.addNext(J)};this._direct=function(J){var K=s(J,"action");return this[K](c.extend({},K in e?e[K]:{},J.args?J.args:J))};this._end=function(){E=false;D.ack();this._run()},this._run=function(){if(E){return}var J=D.get();if(!J){return}E=true;this._proceed(J)};this._proceed=function(J){J=J||{};var O=s(J,"action")||"init",N=O.toLowerCase(),M=true,P=s(J,"target"),L=s(J,"args"),K;if(!H&&u(N)){this.init(c.extend({},e.init,J.args&&J.args.map?J.args.map:J.map?J.map:{}),true)}if(!P&&!L&&(N in this)&&(typeof(this[N])==="function")){this[N](c.extend({},N in e?e[N]:{},J.args?J.args:J))}else{if(P&&(typeof(P)==="object")){if(M=(typeof(P[O])==="function")){K=P[O].apply(P,J.args?J.args:[])}}else{if(H){if(M=(typeof(H[O])==="function")){K=H[O].apply(H,J.args?J.args:[])}}}if(!M&&e.verbose){alert("unknown action : "+O)}this._callback(K,J);this._end()}};this._resolveLatLng=function(J,Q,M,L){var K=s(J,"address"),P,N=this,O=typeof(Q)==="function"?Q:N[Q];if(K){if(!L){L=0}if(typeof(K)==="object"){P=K}else{P={address:K}}l().geocode(P,function(S,R){if(R===google.maps.GeocoderStatus.OK){O.apply(N,[J,M?S:S[0].geometry.location])}else{if((R===google.maps.GeocoderStatus.OVER_QUERY_LIMIT)&&(L<e.queryLimit.attempt)){setTimeout(function(){N._resolveLatLng(J,Q,M,L+1)},e.queryLimit.delay+Math.floor(Math.random()*e.queryLimit.random))}else{if(e.verbose){alert("Geocode error : "+R)}O.apply(N,[J,false])}}})}else{O.apply(N,[J,f(J,false,true)])}};this._resolveAllLatLng=function(J,N,O){var M=this,K=-1,L=function(){do{K++}while((K<J[N].length)&&!("address" in J[N][K]));if(K<J[N].length){(function(P){M._resolveLatLng(P,function(Q,R){Q.latLng=R;L.apply(M,[])})})(J[N][K])}else{M[O](J)}};L()};this._call=function(){var K,L=arguments[0],J=[];if(!arguments.length||!H||(typeof(H[L])!=="function")){return}for(K=1;K<arguments.length;K++){J.push(arguments[K])}return H[L].apply(H,J)};this._subcall=function(J,L){var K={};if(!J.map){return}if(!L){L=s(J.map,"latlng")}if(!H){if(L){K={center:L}}this.init(c.extend({},J.map,K),true)}else{if(J.map.center&&L){this._call("setCenter",L)}if(J.map.zoom!==undefined){this._call("setZoom",J.map.zoom)}if(J.map.mapTypeId!==undefined){this._call("setMapTypeId",J.map.mapTypeId)}}};this._attachEvent=function(K,J,N,M,L){google.maps.event["addListener"+(L?"Once":"")](K,J,function(O){N.apply(I,[K,O,M])})};this._attachEvents=function(L,J){var K;if(!J){return}if(J.events){for(K in J.events){if(typeof(J.events[K])==="function"){this._attachEvent(L,K,J.events[K],J.data,false)}}}if(J.onces){for(K in J.onces){if(typeof(J.onces[K])==="function"){this._attachEvent(L,K,J.onces[K],J.data,true)}}}};this._callback=function(K,J){if(typeof(J.callback)==="function"){J.callback.apply(I,[K])}else{if(typeof(J.callback)==="object"){for(var L=0;L<J.callback.length;L++){if(typeof(J.callback[L])==="function"){J.callback[k].apply(I,[K])}}}}};this._manageEnd=function(K,J,L){var N,M;if(K&&(typeof(K)==="object")){this._attachEvents(K,J);if(J.apply&&J.apply.length){for(N=0;N<J.apply.length;N++){M=J.apply[N];if(!M.action||(typeof(K[M.action])!=="function")){continue}if(M.args){K[M.action].apply(K,M.args)}else{K[M.action]()}}}}if(!L){this._callback(K,J);this._end()}};this.destroy=function(J){var K;F.clear();I.empty();for(K in G){delete G[K]}G={};if(H){delete H}this._callback(null,J);this._end()};this.init=function(J,K){var N,L,M;if(H){return this._end()}N=A("map",J);if((typeof(N.options.center)==="boolean")&&N.options.center){return false}M=c.extend({},e.init,N.options);if(!M.center){M.center=[e.init.center.lat,e.init.center.lng]}M.center=f(M.center);H=new e.classes.Map(I.get(0),M);for(L in G){H.mapTypes.set(L,G[L])}this._manageEnd(H,N,K);return true};this.getlatlng=function(J){this._resolveLatLng(J,"_getLatLng",true)},this._getLatLng=function(J,K){this._manageEnd(K,J)},this.getaddress=function(J,L){var N=f(J,false,true),K=s(J,"address"),O=N?{latLng:N}:(K?(typeof(K)==="string"?{address:K}:K):null),P=s(J,"callback"),M=this;if(!L){L=0}if(O&&typeof(P)==="function"){l().geocode(O,function(S,Q){if((Q===google.maps.GeocoderStatus.OVER_QUERY_LIMIT)&&(L<e.queryLimit.attempt)){setTimeout(function(){M.getaddress(J,L+1)},e.queryLimit.delay+Math.floor(Math.random()*e.queryLimit.random))}else{var R=Q===google.maps.GeocoderStatus.OK?S:false;P.apply(I,[R,Q]);if(!R&&e.verbose){alert("Geocode error : "+Q)}M._end()}})}else{this._end()}};this.getroute=function(J){var L=s(J,"callback"),K=this;if((typeof(L)==="function")&&J.options){J.options.origin=f(J.options.origin,true);J.options.destination=f(J.options.destination,true);a().route(J.options,function(O,M){var N=M==google.maps.DirectionsStatus.OK?O:false;L.apply(I,[N,M]);K._end()})}else{this._end()}};this.getelevation=function(K){var N,R,P,L,O=[],Q=s(K,"callback"),J=s(K,"latlng"),M=this;if(typeof(Q)==="function"){N=function(U,S){var T=S===google.maps.ElevationStatus.OK?U:false;Q.apply(I,[T,S]);M._end()};if(J){O.push(f(J))}else{O=s(K,"locations")||[];if(O){O=g(O);for(L=0;L<O.length;L++){O[L]=f(O[L])}}}if(O.length){r().getElevationForLocations({locations:O},N)}else{R=s(K,"path");P=s(K,"samples");if(R&&P){for(L=0;L<R.length;L++){O.push(f(R[L]))}if(O.length){r().getElevationAlongPath({path:O,samples:P},N)}}}}else{this._end()}};this.getdistance=function(J){var K,M=s(J,"callback"),L=this;if((typeof(M)==="function")&&J.options&&J.options.origins&&J.options.destinations){J.options.origins=g(J.options.origins);for(K=0;K<J.options.origins.length;K++){J.options.origins[K]=f(J.options.origins[K],true)}J.options.destinations=g(J.options.destinations);for(K=0;K<J.options.destinations.length;K++){J.options.destinations[K]=f(J.options.destinations[K],true)}b().getDistanceMatrix(J.options,function(P,N){var O=N==google.maps.DistanceMatrixStatus.OK?P:false;M.apply(I,[O,N]);L._end()})}else{this._end()}};this.addmarker=function(J){this._resolveLatLng(J,"_addMarker")};this._addMarker=function(K,N,L){var J,M,P,O=A("marker",K,"to");if(!L){if(!N){this._manageEnd(false,O);return}this._subcall(K,N)}else{if(!N){return}}if(O.to){P=F.refToObj(O.to);J=P&&(typeof(P.add)==="function");if(J){P.add(N,K);if(typeof(P.redraw)==="function"){P.redraw()}}if(!L){this._manageEnd(J,O)}}else{O.options.position=N;O.options.map=H;J=new e.classes.Marker(O.options);if(C(K,"infowindow")){M=A("infowindow",K.infowindow,"open");if((M.open===undefined)||M.open){M.apply=g(M.apply);M.apply.unshift({action:"open",args:[H,J]})}M.action="addinfowindow";this._planNext(M)}if(!L){F.add("marker",J,O);this._manageEnd(J,O)}}return J};this.addmarkers=function(J){if(s(J,"clusters")){this._resolveAllLatLng(J,"markers","_addclusteredmarkers")}else{this._resolveAllLatLng(J,"markers","_addmarkers")}};this._addmarkers=function(L){var S,J,N,K,P,R={},O,Q,M=s(L,"markers");this._subcall(L);if(typeof(M)!=="object"){return this._end()}J=A("marker",L,["to","markers"]);if(J.to){Q=F.refToObj(J.to);S=Q&&(typeof(Q.add)==="function");if(S){for(N=0;N<M.length;N++){if(K=f(M[N])){Q.add(K,M[N])}}if(typeof(Q.redraw)==="function"){Q.redraw()}}this._manageEnd(S,J)}else{c.extend(true,R,J.options);R.map=H;S=[];for(N=0;N<M.length;N++){if(K=f(M[N])){if(M[N].options){O={};c.extend(true,O,R,M[N].options);J.options=O}else{J.options=R}J.options.position=K;P=new e.classes.Marker(J.options);S.push(P);J.data=M[N].data;J.tag=M[N].tag;F.add("marker",P,J);this._manageEnd(P,J,true)}}J.options=R;this._callback(S,L);this._end()}};this._addclusteredmarkers=function(K){var N,M,J,R,O=this,P=s(K,"radius"),Q=s(K,"maxZoom"),L=s(K,"markers"),S=s(K,"clusters");if(!H.getBounds()){google.maps.event.addListenerOnce(H,"bounds_changed",function(){O._addclusteredmarkers(K)});return}if(typeof(P)==="number"){N=new z();for(M=0;M<L.length;M++){J=f(L[M]);N.add(J,L[M])}R=this._initClusters(K,N,P,Q,S)}this._callback(R,K);this._end()};this._initClusters=function(K,M,J,L,O){var N=this;M.setRedraw(function(Q){var R,P=M.clusters(H,J,L,Q);if(P){R=M.freeDiff(P);N._displayClusters(K,M,P,R,O)}});M.events(google.maps.event.addListener(H,"zoom_changed",function(){M.redraw(true)}),google.maps.event.addListener(H,"bounds_changed",function(){M.redraw()}));M.redraw();return F.add("cluster",M,K)};this._displayClusters=function(N,Y,M,X,O){var W,Z,R,V,T,S,L,aa,J,ac,Q,ab,K,P=C(N,"cluster")?A("",s(N,"cluster")):{},U=C(N,"marker")?A("",s(N,"marker")):{};for(Z=0;Z<M.length;Z++){if(Z in X){continue}aa=M[Z];T=false;if(aa.idx.length>1){V=0;for(W in O){if((W>V)&&(W<=aa.idx.length)){V=W}}if(O[V]){Q=s(O[V],"width");ab=s(O[V],"height");K={};c.extend(true,K,P,{options:{pane:"overlayLayer",content:O[V].content.replace("CLUSTER_COUNT",aa.idx.length),offset:{x:-Q/2,y:-ab/2}}});S=this._addOverlay(K,f(aa),true);K.options.pane="floatShadow";K.options.content=c("<div></div>");K.options.content.width(Q);K.options.content.height(ab);L=this._addOverlay(K,f(aa),true);P.data={latLng:f(aa),markers:[]};for(R=0;R<aa.idx.length;R++){P.data.markers.push(Y.get(aa.idx[R]).marker)}this._attachEvents(L,P);Y.store(aa,S,L);T=true}}if(!T){J={};c.extend(true,J,U.options);for(R=0;R<aa.idx.length;R++){V=Y.get(aa.idx[R]);U.latLng=V.latLng;U.data=V.marker.data;U.tag=V.marker.tag;if(V.marker.options){ac={};c.extend(true,ac,J,V.marker.options);U.options=ac}else{U.options=J}S=this._addMarker(U,U.latLng,true);this._attachEvents(S,U);Y.store(aa,S)}U.options=J}}};this.addinfowindow=function(J){this._resolveLatLng(J,"_addInfoWindow")};this._addInfoWindow=function(J,L){var N,M,K=[];this._subcall(J,L);N=A("infowindow",J,["open","anchor"]);if(L){N.options.position=L}M=new e.classes.InfoWindow(N.options);if((N.open===undefined)||N.open){N.apply=g(N.apply);K.push(H);if(N.anchor){K.push(N.anchor)}N.apply.unshift({action:"open",args:K})}F.add("infowindow",M,N);this._manageEnd(M,N)};this.addpolyline=function(J){this._addPoly(J,"Polyline","path")};this.addpolygon=function(J){this._addPoly(J,"Polygon","paths")};this._addPoly=function(J,M,O){var K,N,L,P=A(M.toLowerCase(),J,O);if(P[O]){P.options[O]=[];for(K=0;K<P[O].length;K++){if(L=f(P[O][K])){P.options[O].push(L)}}}N=new google.maps[M](P.options);N.setMap(H);F.add(M.toLowerCase(),N,P);this._manageEnd(N,P)};this.addcircle=function(J){this._resolveLatLng(J,"_addCircle")};this._addCircle=function(J,K){var M,L=A("circle",J);if(!K){K=f(L.options.center)}if(!K){return this._manageEnd(false,L)}this._subcall(J,K);L.options.center=K;L.options.map=H;M=new e.classes.Circle(L.options);F.add("circle",M,L);this._manageEnd(M,L)};this.addrectangle=function(J){this._resolveLatLng(J,"_addRectangle")};this._addRectangle=function(J,L){var K,M=A("rectangle",J);M.options.bounds=j(M.options.bounds,true);if(!M.options.bounds){return this._manageEnd(false,M)}this._subcall(J,M.options.bounds.getCenter());M.options.map=H;K=new e.classes.Rectangle(M.options);F.add("rectangle",K,M);this._manageEnd(K,M)};this.addoverlay=function(J){this._resolveLatLng(J,"_addOverlay")};this._addOverlay=function(N,L,O){var M,K=A("overlay",N),J=c.extend({pane:"floatPane",content:"",offset:{x:0,y:0}},K.options),R=c("<div></div>"),Q=[];R.css("border","none").css("borderWidth","0px").css("position","absolute");R.append(J.content);function P(){e.classes.OverlayView.call(this);this.setMap(H)}P.prototype=new e.classes.OverlayView();P.prototype.onAdd=function(){var S=this.getPanes();if(J.pane in S){c(S[J.pane]).append(R)}};P.prototype.draw=function(){var S=this.getProjection(),U=S.fromLatLngToDivPixel(L),T=this;R.css("left",(U.x+J.offset.x)+"px").css("top",(U.y+J.offset.y)+"px");c.each(("dblclick click mouseover mousemove mouseout mouseup mousedown").split(" "),function(W,V){Q.push(google.maps.event.addDomListener(R[0],V,function(X){google.maps.event.trigger(T,V)}))});Q.push(google.maps.event.addDomListener(R[0],"contextmenu",function(V){google.maps.event.trigger(T,"rightclick")}))};P.prototype.onRemove=function(){for(var S=0;S<Q.length;S++){google.maps.event.removeListener(Q[S])}R.remove()};P.prototype.hide=function(){R.hide()};P.prototype.show=function(){R.show()};P.prototype.toggle=function(){if(R){if(R.is(":visible")){this.show()}else{this.hide()}}};P.prototype.toggleDOM=function(){if(this.getMap()){this.setMap(null)}else{this.setMap(H)}};P.prototype.getDOMElement=function(){return R[0]};M=new P();if(!O){F.add("overlay",M,K);this._manageEnd(M,K)}return M};this.addfixpanel=function(K){var N=A("fixpanel",K),J=y=0,M,L;if(N.options.content){M=c(N.options.content);if(N.options.left!==undefined){J=N.options.left}else{if(N.options.right!==undefined){J=I.width()-M.width()-N.options.right}else{if(N.options.center){J=(I.width()-M.width())/2}}}if(N.options.top!==undefined){y=N.options.top}else{if(N.options.bottom!==undefined){y=I.height()-M.height()-N.options.bottom}else{if(N.options.middle){y=(I.height()-M.height())/2}}}L=c("<div></div>").css("position","absolute").css("top",y+"px").css("left",J+"px").css("z-index","1000").append(M);I.first().prepend(L);this._attachEvents(H,N);F.add("fixpanel",L,N);this._callback(L,N)}this._end()};this.adddirectionsrenderer=function(J,K){var L,M=A("directionrenderer",J,"panelId");M.options.map=H;L=new google.maps.DirectionsRenderer(M.options);if(M.panelId){L.setPanel(document.getElementById(M.panelId))}F.add("directionrenderer",L,M);this._manageEnd(L,M,K);return L};this.setdirectionspanel=function(J){var K=F.get("directionrenderer"),L=A("directionpanel",J,"id");if(K&&L.id){K.setPanel(document.getElementById(L.id))}this._manageEnd(K,L)};this.setdirections=function(J){var K=F.get("directionrenderer"),L=A("directions",J);if(J){L.options.directions=J.directions?J.directions:(J.options&&J.options.directions?J.options.directions:null)}if(L.options.directions){if(!K){K=this.adddirectionsrenderer(L,true)}else{K.setDirections(L.options.directions)}}this._manageEnd(K,L)};this.setstreetview=function(J){var K,L=A("streetview",J,"id");if(L.options.position){L.options.position=f(L.options.position)}K=new e.classes.StreetViewPanorama(document.getElementById(L.id),L.options);if(K){H.setStreetView(K)}this._manageEnd(K,L)};this.addkmllayer=function(K){var J,L=A("kmllayer",K,"url");L.options.map=H;if(typeof(L.url)==="string"){J=new e.classes.KmlLayer(L.url,L.options)}F.add("kmllayer",J,L);this._manageEnd(J,L)};this.addtrafficlayer=function(J){var L=A("trafficlayer",J),K=F.get("trafficlayer");if(!K){K=new e.classes.TrafficLayer();K.setMap(H);F.add("trafficlayer",K,L)}this._manageEnd(K,L)};this.addbicyclinglayer=function(J){var K=A("bicyclinglayer",J),L=F.get("bicyclinglayer");if(!L){L=new e.classes.BicyclingLayer();L.setMap(H);F.add("bicyclinglayer",L,K)}this._manageEnd(L,K)};this.addgroundoverlay=function(J){var K,L=A("groundoverlay",J,["bounds","url"]);L.bounds=j(L.bounds);if(L.bounds&&(typeof(L.url)==="string")){K=new e.classes.GroundOverlay(L.url,L.bounds);K.setMap(H);F.add("groundoverlay",K,L)}this._manageEnd(K,L)};this.geolatlng=function(J){var K=s(J,"callback");if(typeof(K)==="function"){if(navigator.geolocation){navigator.geolocation.getCurrentPosition(function(L){var M=new google.maps.LatLng(L.coords.latitude,L.coords.longitude);K.apply(I,[M])},function(){var L=false;K.apply(I,[L])})}else{if(google.gears){google.gears.factory.create("beta.geolocation").getCurrentPosition(function(L){var M=new google.maps.LatLng(L.latitude,L.longitude);K.apply(I,[M])},function(){out=false;K.apply(I,[out])})}else{K.apply(I,[false])}}}this._end()};this.addstyledmap=function(J,K){var L=A("styledmap",J,["id","style"]);if(L.style&&L.id&&!G[L.id]){G[L.id]=new e.classes.StyledMapType(L.style,L.options);if(H){H.mapTypes.set(L.id,G[L.id])}}this._manageEnd(G[L.id],L,K)};this.setstyledmap=function(J){var K=A("styledmap",J,["id","style"]);if(K.id){this.addstyledmap(K,true);if(G[K.id]){H.setMapTypeId(K.id);this._callback(G[K.id],J)}}this._manageEnd(G[K.id],K)};this.clear=function(K){var M=g(s(K,"list")||s(K,"name")),L=s(K,"last",false),N=s(K,"first",false),J=s(K,"tag");if(J!==undefined){J=g(J)}F.clear(M,L,N,J);this._end()};this.get=function(K){var L=s(K,"name")||"map",N=s(K,"first"),M=s(K,"all"),J=s(K,"tag");L=L.toLowerCase();if(L==="map"){return H}if(J!==undefined){J=g(J)}if(N){return F.get(L,false,J)}else{if(M){return F.all(L,J)}else{return F.get(L,true,J)}}};this.getmaxzoom=function(J){this._resolveLatLng(J,"_getMaxZoom")};this._getMaxZoom=function(J,L){var M=s(J,"callback"),K=this;if(M&&typeof(M)==="function"){x().getMaxZoomAtLatLng(L,function(N){var O=N.status===google.maps.MaxZoomStatus.OK?N.zoom:false;M.apply(I,[O,N.status]);K._end()})}else{this._end()}};this.setdefault=function(J){B(J);this._end()};this.autofit=function(K,O){var R,Q,M,N,L,P=true,J=new google.maps.LatLngBounds(),S=s(K,"maxZoom",null);R=F.names();for(N=0;N<R.length;N++){Q=F.all(R[N]);for(L=0;L<Q.length;L++){M=Q[L];if(M.getPosition){J.extend(M.getPosition());P=false}else{if(M.getBounds){J.extend(M.getBounds().getNorthEast());J.extend(M.getBounds().getSouthWest());P=false}else{if(M.getPaths){M.getPaths().forEach(function(T){T.forEach(function(U){J.extend(U);P=false})})}else{if(M.getPath){M.getPath().forEach(function(T){J.extend(T);P=false})}else{if(M.getCenter){J.extend(M.getCenter());P=false}}}}}}}if(!P&&(!H.getBounds()||!H.getBounds().equals(J))){if(S!==null){google.maps.event.addListenerOnce(H,"bounds_changed",function(){if(this.getZoom()>S){this.setZoom(S)}})}H.fitBounds(J)}if(!O){this._manageEnd(P?false:J,K,O)}}}c.fn.gmap3=function(){var F,D,H=[],G=true,E=[];for(F=0;F<arguments.length;F++){D=arguments[F]||{};if(typeof(D)==="string"){D={action:D}}H.push(D)}if(!H.length){H.push({})}c.each(this,function(){var I=c(this),J=I.data("gmap3");G=false;if(!J){J=new w(I);I.data("gmap3",J)}if((H.length==1)&&(n(H[0]))){E.push(J._direct(H[0]))}else{J._plan(H)}});if(E.length){if(E.length===1){return E[0]}else{return E}}if(G&&(arguments.length==2)&&(typeof(arguments[0])==="string")&&(arguments[0].toLowerCase()==="setdefault")){B(arguments[1])}return this}}(jQuery)); 10 (function(i,e){var q,x=0;function m(){if(!q){q={verbose:false,queryLimit:{attempt:5,delay:250,random:250},classes:{Map:google.maps.Map,Marker:google.maps.Marker,InfoWindow:google.maps.InfoWindow,Circle:google.maps.Circle,Rectangle:google.maps.Rectangle,OverlayView:google.maps.OverlayView,StreetViewPanorama:google.maps.StreetViewPanorama,KmlLayer:google.maps.KmlLayer,TrafficLayer:google.maps.TrafficLayer,BicyclingLayer:google.maps.BicyclingLayer,GroundOverlay:google.maps.GroundOverlay,StyledMapType:google.maps.StyledMapType,ImageMapType:google.maps.ImageMapType},map:{mapTypeId:google.maps.MapTypeId.ROADMAP,center:[46.578498,2.457275],zoom:2},overlay:{pane:"floatPane",content:"",offset:{x:0,y:0}},geoloc:{getCurrentPosition:{maximumAge:60000,timeout:5000}}}}}function G(K,J){return K!==e?K:"gmap3_"+(J?x+1:++x)}function B(N,J,L,O,M){if(J.todo.events||J.todo.onces){var K={id:O,data:J.todo.data,tag:J.todo.tag}}if(J.todo.events){i.each(J.todo.events,function(P,Q){google.maps.event.addListener(L,P,function(R){Q.apply(N,[M?M:L,R,K])})})}if(J.todo.onces){i.each(J.todo.onces,function(P,Q){google.maps.event.addListenerOnce(L,P,function(R){Q.apply(N,[M?M:L,R,K])})})}}function w(){var J=[];this.empty=function(){return !J.length};this.add=function(K){J.push(K)};this.get=function(){return J.length?J[0]:false};this.ack=function(){J.shift()}}function a(R,J,L){var P={},N=this,O,Q={latLng:{map:false,marker:false,infowindow:false,circle:false,overlay:false,getlatlng:false,getmaxzoom:false,getelevation:false,streetviewpanorama:false,getaddress:true},geoloc:{getgeoloc:true}};if(typeof L==="string"){L=K(L)}function K(T){var S={};S[T]={};return S}function M(){var S;for(S in L){if(S in P){continue}return S}}this.run=function(){var S,T;while(S=M()){if(typeof R[S]==="function"){O=S;T=i.extend(true,{},q[S]||{},L[S].options||{});if(S in Q.latLng){if(L[S].values){F(L[S].values,R,R[S],{todo:L[S],opts:T,session:P})}else{H(R,R[S],Q.latLng[S],{todo:L[S],opts:T,session:P})}}else{if(S in Q.geoloc){D(R,R[S],{todo:L[S],opts:T,session:P})}else{R[S].apply(R,[{todo:L[S],opts:T,session:P}])}}return}else{P[S]=null}}J.apply(R,[L,P])};this.ack=function(S){P[O]=S;N.run.apply(N,[])}}function d(L){var J,K=[];for(J in L){K.push(J)}return K}function v(L,O){var J={};if(L.todo){for(var K in L.todo){if((K!=="options")&&(K!=="values")){J[K]=L.todo[K]}}}var M,N=["data","tag","id","events","onces"];for(M=0;M<N.length;M++){g(J,N[M],O,L.todo)}J.options=i.extend({},L.todo.options||{},O.options||{});return J}function g(L,K){for(var J=2;J<arguments.length;J++){if(K in arguments[J]){L[K]=arguments[J][K];return}}}function E(){var J=[];this.get=function(Q){if(J.length){var N,M,L,P,K,O=d(Q);for(N=0;N<J.length;N++){P=J[N];K=O.length==P.keys.length;for(M=0;(M<O.length)&&K;M++){L=O[M];K=L in P.request;if(K){if((typeof Q[L]==="object")&&("equals" in Q[L])&&(typeof Q[L]==="function")){K=Q[L].equals(P.request[L])}else{K=Q[L]===P.request[L]}}}if(K){return P.results}}}};this.store=function(L,K){J.push({request:L,keys:d(L),results:K})}}function I(O,N,M,J){var L=this,K=[];q.classes.OverlayView.call(this);this.setMap(O);this.onAdd=function(){var P=this.getPanes();if(N.pane in P){i(P[N.pane]).append(J)}i.each("dblclick click mouseover mousemove mouseout mouseup mousedown".split(" "),function(R,Q){K.push(google.maps.event.addDomListener(J[0],Q,function(S){i.Event(S).stopPropagation();google.maps.event.trigger(L,Q,[S])}))});K.push(google.maps.event.addDomListener(J[0],"contextmenu",function(Q){i.Event(Q).stopPropagation();google.maps.event.trigger(L,"rightclick",[Q])}));this.draw()};this.getPosition=function(){return M};this.draw=function(){this.draw=function(){var P=this.getProjection().fromLatLngToDivPixel(M);J.css("left",(P.x+N.offset.x)+"px").css("top",(P.y+N.offset.y)+"px")}};this.onRemove=function(){for(var P=0;P<K.length;P++){google.maps.event.removeListener(K[P])}J.remove()};this.hide=function(){J.hide()};this.show=function(){J.show()};this.toggle=function(){if(J){if(J.is(":visible")){this.show()}else{this.hide()}}};this.toggleDOM=function(){if(this.getMap()){this.setMap(null)}else{this.setMap(O)}};this.getDOMElement=function(){return J[0]}}function f(L){function J(){this.onAdd=function(){};this.onRemove=function(){};this.draw=function(){};return q.classes.OverlayView.apply(this,[])}J.prototype=q.classes.OverlayView.prototype;var K=new J();K.setMap(L);return K}function z(ab,al,O,X){var ak=false,af=false,ac=false,W=false,T=true,S=this,K=[],R={},aa={},ag=[],ae=[],L=[],ah=f(al),V,am,aj,M,N;Q();this.getById=function(an){return an in aa?ag[aa[an]]:false};this.clearById=function(ao){if(ao in aa){var an=aa[ao];if(ag[an]){ag[an].setMap(null)}delete ag[an];ag[an]=false;delete ae[an];ae[an]=false;delete L[an];L[an]=false;delete aa[ao];af=true}};this.add=function(an,ao){an.id=G(an.id);this.clearById(an.id);aa[an.id]=ag.length;ag.push(null);ae.push(an);L.push(ao);af=true};this.addMarker=function(ao,an){an=an||{};an.id=G(an.id);this.clearById(an.id);if(!an.options){an.options={}}an.options.position=ao.getPosition();B(ab,{todo:an},ao,an.id);aa[an.id]=ag.length;ag.push(ao);ae.push(an);L.push(an.data||{});af=true};this.todo=function(an){return ae[an]};this.value=function(an){return L[an]};this.marker=function(an){return ag[an]};this.setMarker=function(ao,an){ag[ao]=an};this.store=function(an,ao,ap){R[an.ref]={obj:ao,shadow:ap}};this.free=function(){for(var an=0;an<K.length;an++){google.maps.event.removeListener(K[an])}K=[];i.each(R,function(ao){Z(ao)});R={};i.each(ae,function(ao){ae[ao]=null});ae=[];i.each(ag,function(ao){if(ag[ao]){ag[ao].setMap(null);delete ag[ao]}});ag=[];i.each(L,function(ao){delete L[ao]});L=[];aa={}};this.filter=function(an){aj=an;ad()};this.enable=function(an){if(T!=an){T=an;ad()}};this.display=function(an){M=an};this.error=function(an){N=an};this.beginUpdate=function(){ak=true};this.endUpdate=function(){ak=false;if(af){ad()}};function Q(){am=ah.getProjection();if(!am){setTimeout(function(){Q.apply(S,[])},25);return}W=true;K.push(google.maps.event.addListener(al,"zoom_changed",function(){ai()}));K.push(google.maps.event.addListener(al,"bounds_changed",function(){ai()}));ad()}function Z(an){if(typeof R[an]==="object"){if(typeof(R[an].obj.setMap)==="function"){R[an].obj.setMap(null)}if(typeof(R[an].obj.remove)==="function"){R[an].obj.remove()}if(typeof(R[an].shadow.remove)==="function"){R[an].obj.remove()}if(typeof(R[an].shadow.setMap)==="function"){R[an].shadow.setMap(null)}delete R[an].obj;delete R[an].shadow}else{if(ag[an]){ag[an].setMap(null)}}delete R[an]}function J(){var av,au,at,aq,ar,ap,ao,an;if(arguments[0] instanceof google.maps.LatLng){av=arguments[0].lat();at=arguments[0].lng();if(arguments[1] instanceof google.maps.LatLng){au=arguments[1].lat();aq=arguments[1].lng()}else{au=arguments[1];aq=arguments[2]}}else{av=arguments[0];at=arguments[1];if(arguments[2] instanceof google.maps.LatLng){au=arguments[2].lat();aq=arguments[2].lng()}else{au=arguments[2];aq=arguments[3]}}ar=Math.PI*av/180;ap=Math.PI*at/180;ao=Math.PI*au/180;an=Math.PI*aq/180;return 1000*6371*Math.acos(Math.min(Math.cos(ar)*Math.cos(ao)*Math.cos(ap)*Math.cos(an)+Math.cos(ar)*Math.sin(ap)*Math.cos(ao)*Math.sin(an)+Math.sin(ar)*Math.sin(ao),1))}function P(){var an=J(al.getCenter(),al.getBounds().getNorthEast()),ao=new google.maps.Circle({center:al.getCenter(),radius:1.25*an});return ao.getBounds()}function U(){var ao={},an;for(an in R){ao[an]=true}return ao}function ai(){clearTimeout(V);V=setTimeout(function(){ad()},25)}function Y(ao){var aq=am.fromLatLngToDivPixel(ao),ap=am.fromDivPixelToLatLng(new google.maps.Point(aq.x+O,aq.y-O)),an=am.fromDivPixelToLatLng(new google.maps.Point(aq.x-O,aq.y+O));return new google.maps.LatLngBounds(an,ap)}function ad(){if(ak||ac||!W){return}var az=[],aB={},aA=al.getZoom(),aC=(X!==e)&&(aA>X),at=U(),ar,aq,ap,aw,ax,av,au,ao=false,an,ay;af=false;if(aA>3){an=P();ao=an.getSouthWest().lng()<an.getNorthEast().lng()}i.each(ae,function(aE,aD){if(!aD){return}if(ao&&(!an.contains(aD.options.position))){return}if(aj&&!aj(L[aE])){return}az.push(aE)});while(1){ar=0;while(aB[ar]&&(ar<az.length)){ar++}if(ar==az.length){break}av=[];if(T&&!aC){do{au=av;av=[];if(au.length){aw=ax=0;for(ap=0;ap<au.length;ap++){aw+=ae[az[au[ap]]].options.position.lat();ax+=ae[az[au[ap]]].options.position.lng()}aw/=au.length;ax/=au.length;an=Y(new google.maps.LatLng(aw,ax))}else{an=Y(ae[az[ar]].options.position)}for(aq=ar;aq<az.length;aq++){if(aB[aq]){continue}if(an.contains(ae[az[aq]].options.position)){av.push(aq)}}}while((au.length<av.length)&&(av.length>1))}else{for(aq=ar;aq<az.length;aq++){if(aB[aq]){continue}av.push(aq);break}}ay={latLng:an.getCenter(),indexes:[],ref:[]};for(ap=0;ap<av.length;ap++){aB[av[ap]]=true;ay.indexes.push(az[av[ap]]);ay.ref.push(az[av[ap]])}ay.ref=ay.ref.join("-");if(ay.ref in at){delete at[ay.ref]}else{if(av.length===1){R[ay.ref]=true}(function(aD){setTimeout(function(){M(aD)},1)})(ay)}}i.each(at,function(aD){Z(aD)});ac=false}}function C(K,J){this.id=function(){return K};this.filter=function(L){J.filter(L)};this.enable=function(){J.enable(true)};this.disable=function(){J.enable(false)};this.add=function(M,L,N){if(!N){J.beginUpdate()}J.addMarker(M,L);if(!N){J.endUpdate()}};this.getById=function(L){return J.getById(L)};this.clearById=function(M,L){if(!L){J.beginUpdate()}J.clearById(M);if(!L){J.endUpdate()}}}function u(){var L={},M={};function K(O){if(O){if(typeof O==="function"){return O}O=l(O);return function(Q){if(Q===e){return false}if(typeof Q==="object"){for(var P=0;P<Q.length;P++){if(i.inArray(Q[P],O)>=0){return true}}return false}return i.inArray(Q,O)>=0}}}function J(O){return{id:O.id,name:O.name,object:O.obj,tag:O.tag,data:O.data}}this.add=function(Q,P,S,R){var O=Q.todo||{},T=G(O.id);if(!L[P]){L[P]=[]}if(T in M){this.clearById(T)}M[T]={obj:S,sub:R,name:P,id:T,tag:O.tag,data:O.data};L[P].push(T);return T};this.getById=function(Q,P,O){if(Q in M){if(P){return M[Q].sub}else{if(O){return J(M[Q])}}return M[Q].obj}return false};this.get=function(Q,S,O,R){var U,T,P=K(O);if(!L[Q]||!L[Q].length){return null}U=L[Q].length;while(U){U--;T=L[Q][S?U:L[Q].length-U-1];if(T&&M[T]){if(P&&!P(M[T].tag)){continue}return R?J(M[T]):M[T].obj}}return null};this.all=function(R,P,S){var O=[],Q=K(P),T=function(W){var U,V;for(U=0;U<L[W].length;U++){V=L[W][U];if(V&&M[V]){if(Q&&!Q(M[V].tag)){continue}O.push(S?J(M[V]):M[V].obj)}}};if(R in L){T(R)}else{if(R===e){for(R in L){T(R)}}}return O};function N(O){if(typeof(O.setMap)==="function"){O.setMap(null)}if(typeof(O.remove)==="function"){O.remove()}if(typeof(O.free)==="function"){O.free()}O=null}this.rm=function(R,P,Q){var O,S;if(!L[R]){return false}if(P){if(Q){for(O=L[R].length-1;O>=0;O--){S=L[R][O];if(P(M[S].tag)){break}}}else{for(O=0;O<L[R].length;O++){S=L[R][O];if(P(M[S].tag)){break}}}}else{O=Q?L[R].length-1:0}if(!(O in L[R])){return false}return this.clearById(L[R][O],O)};this.clearById=function(R,O){if(R in M){var Q,P=M[R].name;for(Q=0;O===e&&Q<L[P].length;Q++){if(R===L[P][Q]){O=Q}}N(M[R].obj);if(M[R].sub){N(M[R].sub)}delete M[R];L[P].splice(O,1);return true}return false};this.objGetById=function(Q){var P;if(L.clusterer){for(var O in L.clusterer){if((P=M[L.clusterer[O]].obj.getById(Q))!==false){return P}}}return false};this.objClearById=function(P){if(L.clusterer){for(var O in L.clusterer){if(M[L.clusterer[O]].obj.clearById(P)){return true}}}return null};this.clear=function(U,T,V,O){var Q,S,R,P=K(O);if(!U||!U.length){U=[];for(Q in L){U.push(Q)}}else{U=l(U)}for(S=0;S<U.length;S++){if(U[S]){R=U[S];if(!L[R]){continue}if(T){this.rm(R,P,true)}else{if(V){this.rm(R,P,false)}else{while(this.rm(R,P,false)){}}}}}}}var c={},t=new E();function p(){if(!c.geocoder){c.geocoder=new google.maps.Geocoder()}return c.geocoder}function r(){if(!c.directionsService){c.directionsService=new google.maps.DirectionsService()}return c.directionsService}function s(){if(!c.elevationService){c.elevationService=new google.maps.ElevationService()}return c.elevationService}function h(){if(!c.maxZoomService){c.maxZoomService=new google.maps.MaxZoomService()}return c.maxZoomService}function b(){if(!c.distanceMatrixService){c.distanceMatrixService=new google.maps.DistanceMatrixService()}return c.distanceMatrixService}function y(){if(q.verbose){var J,K=[];if(window.console&&(typeof console.error==="function")){for(J=0;J<arguments.length;J++){K.push(arguments[J])}console.error.apply(console,K)}else{K="";for(J=0;J<arguments.length;J++){K+=arguments[J].toString()+" "}alert(K)}}}function j(J){return(typeof(J)==="number"||typeof(J)==="string")&&J!==""&&!isNaN(J)}function l(L){var K,J=[];if(L!==e){if(typeof(L)==="object"){if(typeof(L.length)==="number"){J=L}else{for(K in L){J.push(L[K])}}}else{J.push(L)}}return J}function k(K,M,J){var L=M?K:null;if(!K||(typeof K==="string")){return L}if(K.latLng){return k(K.latLng)}if(K instanceof google.maps.LatLng){return K}else{if(j(K.lat)){return new google.maps.LatLng(K.lat,K.lng)}else{if(!J&&i.isArray(K)){if(!j(K[0])||!j(K[1])){return L}return new google.maps.LatLng(K[0],K[1])}}}return L}function n(K){var L,J;if(!K||K instanceof google.maps.LatLngBounds){return K||null}if(i.isArray(K)){if(K.length==2){L=k(K[0]);J=k(K[1])}else{if(K.length==4){L=k([K[0],K[1]]);J=k([K[2],K[3]])}}}else{if(("ne" in K)&&("sw" in K)){L=k(K.ne);J=k(K.sw)}else{if(("n" in K)&&("e" in K)&&("s" in K)&&("w" in K)){L=k([K.n,K.e]);J=k([K.s,K.w])}}}if(L&&J){return new google.maps.LatLngBounds(J,L)}return null}function H(R,J,M,Q,N){var L=M?k(Q.todo,false,true):false,P=L?{latLng:L}:(Q.todo.address?(typeof(Q.todo.address)==="string"?{address:Q.todo.address}:Q.todo.address):false),K=P?t.get(P):false,O=this;if(P){N=N||0;if(K){Q.latLng=K.results[0].geometry.location;Q.results=K.results;Q.status=K.status;J.apply(R,[Q])}else{if(P.location){P.location=k(P.location)}if(P.bounds){P.bounds=n(P.bounds)}p().geocode(P,function(T,S){if(S===google.maps.GeocoderStatus.OK){t.store(P,{results:T,status:S});Q.latLng=T[0].geometry.location;Q.results=T;Q.status=S;J.apply(R,[Q])}else{if((S===google.maps.GeocoderStatus.OVER_QUERY_LIMIT)&&(N<q.queryLimit.attempt)){setTimeout(function(){H.apply(O,[R,J,M,Q,N+1])},q.queryLimit.delay+Math.floor(Math.random()*q.queryLimit.random))}else{y("geocode failed",S,P);Q.latLng=Q.results=false;Q.status=S;J.apply(R,[Q])}}})}}else{Q.latLng=k(Q.todo,false,true);J.apply(R,[Q])}}function F(O,J,P,K){var M=this,L=-1;function N(){do{L++}while((L<O.length)&&!("address" in O[L]));if(L>=O.length){P.apply(J,[K]);return}H(M,function(Q){delete Q.todo;i.extend(O[L],Q);N.apply(M,[])},true,{todo:O[L]})}N()}function D(J,M,K){var L=false;if(navigator&&navigator.geolocation){navigator.geolocation.getCurrentPosition(function(N){if(L){return}L=true;K.latLng=new google.maps.LatLng(N.coords.latitude,N.coords.longitude);M.apply(J,[K])},function(){if(L){return}L=true;K.latLng=false;M.apply(J,[K])},K.opts.getCurrentPosition)}else{K.latLng=false;M.apply(J,[K])}}function A(R){var Q=this,S=new w(),T=new u(),L=null,N;this._plan=function(X){for(var W=0;W<X.length;W++){S.add(new a(Q,P,X[W]))}O()};function O(){if(!N&&(N=S.get())){N.run()}}function P(){N=null;S.ack();O.call(Q)}function V(W){var X,Y=[];for(X=1;X<arguments.length;X++){Y.push(arguments[X])}if(typeof W.todo.callback==="function"){W.todo.callback.apply(R,Y)}else{if(typeof W.todo.callback==="object"){i.each(W.todo.callback,function(aa,Z){if(typeof Z==="function"){Z.apply(R,Y)}})}}}function M(W,X,Y){if(Y){B(R,W,X,Y)}V(W,X);N.ack(X)}function J(Y,W){W=W||{};if(L){if(W.todo&&W.todo.options){L.setOptions(W.todo.options)}}else{var X=W.opts||i.extend(true,{},q.map,W.todo&&W.todo.options?W.todo.options:{});X.center=Y||k(X.center);L=new q.classes.Map(R.get(0),X)}}this.map=function(W){J(W.latLng,W);B(R,W,L);M(W,L)};this.destroy=function(W){T.clear();R.empty();if(L){L=null}M(W,true)};this.infowindow=function(X){var Y=[],W="values" in X.todo;if(!W){if(X.latLng){X.opts.position=X.latLng}else{if(X.opts.position){X.opts.position=k(X.opts.position)}}X.todo.values=[{options:X.opts}]}i.each(X.todo.values,function(aa,ab){var ad,ac,Z=v(X,ab);if(!L){J(Z.options.position)}ac=new q.classes.InfoWindow(Z.options);if(ac&&((Z.open===e)||Z.open)){if(W){ac.open(L,Z.anchor?Z.anchor:e)}else{ac.open(L,Z.anchor?Z.anchor:(X.latLng?e:(X.session.marker?X.session.marker:e)))}}Y.push(ac);ad=T.add({todo:Z},"infowindow",ac);B(R,{todo:Z},ac,ad)});M(X,W?Y:Y[0])};this.circle=function(X){var Y=[],W="values" in X.todo;if(!W){X.opts.center=X.latLng||k(X.opts.center);X.todo.values=[{options:X.opts}]}if(!X.todo.values.length){M(X,false);return}i.each(X.todo.values,function(aa,ab){var ad,ac,Z=v(X,ab);Z.options.center=Z.options.center?k(Z.options.center):k(ab);if(!L){J(Z.options.center)}Z.options.map=L;ac=new q.classes.Circle(Z.options);Y.push(ac);ad=T.add({todo:Z},"circle",ac);B(R,{todo:Z},ac,ad)});M(X,W?Y:Y[0])};this.overlay=function(Y,X){var aa,Z,W=i(document.createElement("div")).css("border","none").css("borderWidth","0px").css("position","absolute");W.append(Y.opts.content);I.prototype=new q.classes.OverlayView();Z=new I(L,Y.opts,Y.latLng,W);W=null;if(X){return Z}aa=T.add(Y,"overlay",Z);M(Y,Z,aa)};this.getaddress=function(W){V(W,W.results,W.status);N.ack()};this.getlatlng=function(W){V(W,W.results,W.status);N.ack()};this.getmaxzoom=function(W){h().getMaxZoomAtLatLng(W.latLng,function(X){V(W,X.status===google.maps.MaxZoomStatus.OK?X.zoom:false,status);N.ack()})};this.getelevation=function(X){var Y,W=[],Z=function(ab,aa){V(X,aa===google.maps.ElevationStatus.OK?ab:false,aa);N.ack()};if(X.latLng){W.push(X.latLng)}else{W=l(X.todo.locations||[]);for(Y=0;Y<W.length;Y++){W[Y]=k(W[Y])}}if(W.length){s().getElevationForLocations({locations:W},Z)}else{if(X.todo.path&&X.todo.path.length){for(Y=0;Y<X.todo.path.length;Y++){W.push(k(X.todo.path[Y]))}}if(W.length){s().getElevationAlongPath({path:W,samples:X.todo.samples},Z)}else{N.ack()}}};this.defaults=function(W){i.each(W.todo,function(X,Y){if(typeof q[X]==="object"){q[X]=i.extend({},q[X],Y)}else{q[X]=Y}});N.ack(true)};this.rectangle=function(X){var Y=[],W="values" in X.todo;if(!W){X.todo.values=[{options:X.opts}]}if(!X.todo.values.length){M(X,false);return}i.each(X.todo.values,function(aa,ab){var ad,ac,Z=v(X,ab);Z.options.bounds=Z.options.bounds?n(Z.options.bounds):n(ab);if(!L){J(Z.options.bounds.getCenter())}Z.options.map=L;ac=new q.classes.Rectangle(Z.options);Y.push(ac);ad=T.add({todo:Z},"rectangle",ac);B(R,{todo:Z},ac,ad)});M(X,W?Y:Y[0])};function K(X,Y,Z){var aa=[],W="values" in X.todo;if(!W){X.todo.values=[{options:X.opts}]}if(!X.todo.values.length){M(X,false);return}J();i.each(X.todo.values,function(ad,af){var ah,ae,ac,ag,ab=v(X,af);if(ab.options[Z]){if(ab.options[Z][0][0]&&i.isArray(ab.options[Z][0][0])){for(ae=0;ae<ab.options[Z].length;ae++){for(ac=0;ac<ab.options[Z][ae].length;ac++){ab.options[Z][ae][ac]=k(ab.options[Z][ae][ac])}}}else{for(ae=0;ae<ab.options[Z].length;ae++){ab.options[Z][ae]=k(ab.options[Z][ae])}}}ab.options.map=L;ag=new google.maps[Y](ab.options);aa.push(ag);ah=T.add({todo:ab},Y.toLowerCase(),ag);B(R,{todo:ab},ag,ah)});M(X,W?aa:aa[0])}this.polyline=function(W){K(W,"Polyline","path")};this.polygon=function(W){K(W,"Polygon","paths")};this.trafficlayer=function(W){J();var X=T.get("trafficlayer");if(!X){X=new q.classes.TrafficLayer();X.setMap(L);T.add(W,"trafficlayer",X)}M(W,X)};this.bicyclinglayer=function(W){J();var X=T.get("bicyclinglayer");if(!X){X=new q.classes.BicyclingLayer();X.setMap(L);T.add(W,"bicyclinglayer",X)}M(W,X)};this.groundoverlay=function(W){W.opts.bounds=n(W.opts.bounds);if(W.opts.bounds){J(W.opts.bounds.getCenter())}var Y,X=new q.classes.GroundOverlay(W.opts.url,W.opts.bounds,W.opts.opts);X.setMap(L);Y=T.add(W,"groundoverlay",X);M(W,X,Y)};this.streetviewpanorama=function(W){if(!W.opts.opts){W.opts.opts={}}if(W.latLng){W.opts.opts.position=W.latLng}else{if(W.opts.opts.position){W.opts.opts.position=k(W.opts.opts.position)}}if(W.todo.divId){W.opts.container=document.getElementById(W.todo.divId)}else{if(W.opts.container){W.opts.container=i(W.opts.container).get(0)}}var Y,X=new q.classes.StreetViewPanorama(W.opts.container,W.opts.opts);if(X){L.setStreetView(X)}Y=T.add(W,"streetviewpanorama",X);M(W,X,Y)};this.kmllayer=function(X){var Y=[],W="values" in X.todo;if(!W){X.todo.values=[{options:X.opts}]}if(!X.todo.values.length){M(X,false);return}i.each(X.todo.values,function(aa,ab){var ad,ac,Z=v(X,ab);if(!L){J()}Z.options.opts.map=L;ac=new q.classes.KmlLayer(Z.options.url,Z.options.opts);Y.push(ac);ad=T.add({todo:Z},"kmllayer",ac);B(R,{todo:Z},ac,ad)});M(X,W?Y:Y[0])};this.panel=function(Z){J();var ab,W=0,aa=0,Y,X=i(document.createElement("div"));X.css("position","absolute").css("z-index","1000");if(Z.opts.content){Y=i(Z.opts.content);if(Z.opts.left!==e){W=Z.opts.left}else{if(Z.opts.right!==e){W=R.width()-Y.width()-Z.opts.right}else{if(Z.opts.center){W=(R.width()-Y.width())/2}}}if(Z.opts.top!==e){aa=Z.opts.top}else{if(Z.opts.bottom!==e){aa=R.height()-Y.height()-Z.opts.bottom}else{if(Z.opts.middle){aa=(R.height()-Y.height())/2}}}X.css("top",aa+"px").css("left",W+"px").append(Y)}R.first().prepend(X);ab=T.add(Z,"panel",X);M(Z,X,ab);X=null};function U(Y){var ac=new z(R,L,Y.radius,Y.maxZoom),W={},Z={},ab=/^[0-9]+$/,aa,X;for(X in Y){if(ab.test(X)){Z[X]=Y[X];Z[X].width=Z[X].width||0;Z[X].height=Z[X].height||0}else{W[X]=Y[X]}}if(W.calculator){aa=function(ad){var ae=[];i.each(ad,function(ag,af){ae.push(ac.value(af))});return W.calculator.apply(R,[ae])}}else{aa=function(ad){return ad.length}}ac.error(function(){y.apply(Q,arguments)});ac.display(function(ad){var ae,ag,ak=0,aj,ah,ai,af=aa(ad.indexes);if(af>1){for(ae in Z){ae=1*ae;if(ae>ak&&ae<=af){ak=ae}}ag=Z[ak]}if(ag){ai=ag.offset||[-ag.width/2,-ag.height/2];aj=i.extend({},W);aj.options=i.extend({pane:"overlayLayer",content:ag.content?ag.content.replace("CLUSTER_COUNT",af):"",offset:{x:("x" in ai?ai.x:ai[0])||0,y:("y" in ai?ai.y:ai[1])||0}},W.options||{});ah=Q.overlay({todo:aj,opts:aj.options,latLng:k(ad)},true);aj.options.pane="floatShadow";aj.options.content=i(document.createElement("div")).width(ag.width+"px").height(ag.height+"px");shadow=Q.overlay({todo:aj,opts:aj.options,latLng:k(ad)},true);W.data={latLng:k(ad),markers:[]};i.each(ad.indexes,function(am,al){W.data.markers.push(ac.value(al));if(ac.marker(al)){ac.marker(al).setMap(null)}});B(R,{todo:W},shadow,e,{main:ah,shadow:shadow});ac.store(ad,ah,shadow)}else{i.each(ad.indexes,function(ao,an){if(ac.marker(an)){ac.marker(an).setMap(L)}else{var al=ac.todo(an),am=new q.classes.Marker(al.options);ac.setMarker(an,am);B(R,{todo:al},am,al.id)}})}});return ac}this.marker=function(Y){var W="values" in Y.todo,ab=!L;if(!W){Y.opts.position=Y.latLng||k(Y.opts.position);Y.todo.values=[{options:Y.opts}]}if(!Y.todo.values.length){M(Y,false);return}if(ab){J()}if(Y.todo.cluster&&!L.getBounds()){google.maps.event.addListenerOnce(L,"bounds_changed",function(){Q.marker.apply(Q,[Y])});return}if(Y.todo.cluster){var X,Z;if(Y.todo.cluster instanceof C){X=Y.todo.cluster;Z=T.getById(X.id(),true)}else{Z=U(Y.todo.cluster);X=new C(G(Y.todo.id,true),Z);T.add(Y,"clusterer",X,Z)}Z.beginUpdate();i.each(Y.todo.values,function(ad,ae){var ac=v(Y,ae);ac.options.position=ac.options.position?k(ac.options.position):k(ae);ac.options.map=L;if(ab){L.setCenter(ac.options.position);ab=false}Z.add(ac,ae)});Z.endUpdate();M(Y,X)}else{var aa=[];i.each(Y.todo.values,function(ad,ae){var ag,af,ac=v(Y,ae);ac.options.position=ac.options.position?k(ac.options.position):k(ae);ac.options.map=L;if(ab){L.setCenter(ac.options.position);ab=false}af=new q.classes.Marker(ac.options);aa.push(af);ag=T.add({todo:ac},"marker",af);B(R,{todo:ac},af,ag)});M(Y,W?aa:aa[0])}};this.getroute=function(W){W.opts.origin=k(W.opts.origin,true);W.opts.destination=k(W.opts.destination,true);r().route(W.opts,function(Y,X){V(W,X==google.maps.DirectionsStatus.OK?Y:false,X);N.ack()})};this.directionsrenderer=function(W){W.opts.map=L;var Y,X=new google.maps.DirectionsRenderer(W.opts);if(W.todo.divId){X.setPanel(document.getElementById(W.todo.divId))}else{if(W.todo.container){X.setPanel(i(W.todo.container).get(0))}}Y=T.add(W,"directionrenderer",X);M(W,X,Y)};this.getgeoloc=function(W){M(W,W.latLng)};this.styledmaptype=function(W){J();var X=new q.classes.StyledMapType(W.todo.styles,W.opts);L.mapTypes.set(W.todo.id,X);M(W,X)};this.imagemaptype=function(W){J();var X=new q.classes.ImageMapType(W.opts);L.mapTypes.set(W.todo.id,X);M(W,X)};this.autofit=function(W){var X=new google.maps.LatLngBounds();i.each(T.all(),function(Y,Z){if(Z.getPosition){X.extend(Z.getPosition())}else{if(Z.getBounds){X.extend(Z.getBounds().getNorthEast());X.extend(Z.getBounds().getSouthWest())}else{if(Z.getPaths){Z.getPaths().forEach(function(aa){aa.forEach(function(ab){X.extend(ab)})})}else{if(Z.getPath){Z.getPath().forEach(function(aa){X.extend(aa);""})}else{if(Z.getCenter){X.extend(Z.getCenter())}}}}}});if(!X.isEmpty()&&(!L.getBounds()||!L.getBounds().equals(X))){if("maxZoom" in W.todo){google.maps.event.addListenerOnce(L,"bounds_changed",function(){if(this.getZoom()>W.todo.maxZoom){this.setZoom(W.todo.maxZoom)}})}L.fitBounds(X)}M(W,true)};this.clear=function(W){if(typeof W.todo==="string"){if(T.clearById(W.todo)||T.objClearById(W.todo)){M(W,true);return}W.todo={name:W.todo}}if(W.todo.id){i.each(l(W.todo.id),function(X,Y){T.clearById(Y)})}else{T.clear(l(W.todo.name),W.todo.last,W.todo.first,W.todo.tag)}M(W,true)};this.exec=function(W){var X=this;i.each(l(W.todo.func),function(Y,Z){i.each(X.get(W.todo,true,W.todo.hasOwnProperty("full")?W.todo.full:true),function(aa,ab){Z.call(R,ab)})});M(W,true)};this.get=function(Y,ab,aa){var X,Z,W=ab?Y:Y.todo;if(!ab){aa=W.full}if(typeof W==="string"){Z=T.getById(W,false,aa)||T.objGetById(W);if(Z===false){X=W;W={}}}else{X=W.name}if(X==="map"){Z=L}if(!Z){Z=[];if(W.id){i.each(l(W.id),function(ac,ad){Z.push(T.getById(ad,false,aa)||T.objGetById(ad))});if(!i.isArray(W.id)){Z=Z[0]}}else{i.each(X?l(X):[e],function(ad,ae){var ac;if(W.first){ac=T.get(ae,false,W.tag,aa);if(ac){Z.push(ac)}}else{if(W.all){i.each(T.all(ae,W.tag,aa),function(ag,af){Z.push(af)})}else{ac=T.get(ae,true,W.tag,aa);if(ac){Z.push(ac)}}}});if(!W.all&&!i.isArray(X)){Z=Z[0]}}}Z=i.isArray(Z)||!W.all?Z:[Z];if(ab){return Z}else{M(Y,Z)}};this.getdistance=function(W){var X;W.opts.origins=l(W.opts.origins);for(X=0;X<W.opts.origins.length;X++){W.opts.origins[X]=k(W.opts.origins[X],true)}W.opts.destinations=l(W.opts.destinations);for(X=0;X<W.opts.destinations.length;X++){W.opts.destinations[X]=k(W.opts.destinations[X],true)}b().getDistanceMatrix(W.opts,function(Z,Y){V(W,Y===google.maps.DistanceMatrixStatus.OK?Z:false,Y);N.ack()})};this.trigger=function(X){if(typeof X.todo==="string"){google.maps.event.trigger(L,X.todo)}else{var W=[L,X.todo.eventName];if(X.todo.var_args){i.each(X.todo.var_args,function(Z,Y){W.push(Y)})}google.maps.event.trigger.apply(google.maps.event,W)}V(X);N.ack()}}function o(K){var J;if(!typeof K==="object"||!K.hasOwnProperty("get")){return false}for(J in K){if(J!=="get"){return false}}return !K.get.hasOwnProperty("callback")}i.fn.gmap3=function(){var K,M=[],L=true,J=[];m();for(K=0;K<arguments.length;K++){if(arguments[K]){M.push(arguments[K])}}if(!M.length){M.push("map")}i.each(this,function(){var N=i(this),O=N.data("gmap3");L=false;if(!O){O=new A(N);N.data("gmap3",O)}if(M.length===1&&(M[0]==="get"||o(M[0]))){J.push(O.get(M[0]==="get"?"map":M[0].get,true))}else{O._plan(M)}});if(J.length){if(J.length===1){return J[0]}else{return J}}return this}})(jQuery); -
lazyest-maps/trunk/js/lazyest-maps.js
r566876 r695801 12 12 }, 13 13 { action: "addMarkers", 14 markers: lazyestMarkers[mapID],15 14 marker:{ 15 values: lazyestMarkers[mapID], 16 16 options:{ 17 17 icon: new google.maps.MarkerImage( photoMarker ), … … 20 20 }, 21 21 events:{ 22 click: function(marker, event, data){ 23 var map = $(this).gmap3("get"),infowindow = $(this).gmap3({ 24 action:"get", 25 name:"infowindow" 26 }); 22 click: function(marker, event, object){ 23 var map = $(this).gmap3("get"),infowindow = $(this).gmap3({get:{name:"infowindow"}}); 27 24 if (infowindow){ 28 infowindow.setContent(data);29 25 infowindow.open(map, marker); 26 infowindow.setContent(object.data); 30 27 } else { 31 28 $(this).gmap3({ 32 action:"addinfowindow", 33 anchor:marker, 34 options:{ 35 content: data 29 infowindow:{ 30 anchor:marker, 31 options:{content: object.data} 36 32 } 37 33 }); … … 41 37 } 42 38 }, 43 { action: "autofit" }39 "autofit" 44 40 ); 45 41 } -
lazyest-maps/trunk/lazyest-maps.php
r662948 r695801 7 7 Author: Brimosoft 8 8 Author URI: http://brimosoft.nl 9 Version: 0. 59 Version: 0.6.0 10 10 License: GNU GPLv3 11 11 */ … … 17 17 * @subpackage Lazyest Maps 18 18 * @author Marcel Brinkkemper 19 * @copyright 2012 Marcel Brinkkemper19 * @copyright 2012-2013 Marcel Brinkkemper 20 20 * @version 0.4 21 21 * @access public … … 164 164 */ 165 165 function register_scripts() { 166 wp_register_script( 'google-maps', 'http://maps.googleapis.com/maps/api/js?sensor=false', array( 'jquery' ), 'V3', true ); 167 wp_register_script( 'gmap', plugins_url( 'js/gmap3.min.js', __FILE__ ), array( 'google-maps'), '4.1', true ); 168 wp_register_script( 'lazyest-maps', plugins_url( 'js/lazyest-maps.js', __FILE__ ), array( 'gmap'), $this->version(), true ); 166 $j = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'js' : 'min.js'; 167 wp_register_script( 'google-maps', 'http://maps.googleapis.com/maps/api/js?sensor=false', array( 'jquery' ), 'V3', true ); 168 wp_register_script( 'gmap', plugins_url( "js/gmap3.$j", __FILE__ ), array( 'google-maps' ), '5.0b', true ); 169 wp_register_script( 'lazyest-maps', plugins_url( "js/lazyest-maps.$j", __FILE__ ), array( 'gmap' ), $this->version(), true ); 169 170 } 170 171 -
lazyest-maps/trunk/readme.txt
r663103 r695801 5 5 Requires at least: 3.4 6 6 Tested up to: 3.5.1 7 Stable tag: 0. 57 Stable tag: 0.6.0 8 8 License: GPLv3 or later 9 9 This plugin shows your Lazyest Gallery images location on a Google Map. … … 18 18 This plugin uses [Google Maps API v3](https://developers.google.com/maps/documentation/javascript/tutorial) and the [GMAP3](http://gmap3.net/) jQuery plugin 19 19 20 = Inversion 0.4.0 =20 = Since version 0.4.0 = 21 21 * Map for images in a folder. It uses simple info windows to display thumbnail over marker 22 22 * Button in Folder Manager to (re)read Geo Data from your images. … … 42 42 == Upgrade Notice == 43 43 44 = 0. 5=45 * Bug fix for Longitude calculation44 = 0.6.0 = 45 * Upgrade to GMAP3 version 5.0b 46 46 47 47 == Changelog == 48 49 = 0.6.0 = 50 * Changed: GMAP3 library upgraded from 4.1 to 5.0b 51 * Changed: Settings screen lay out 52 48 53 = 0.5 = 49 54 * Bug fix: Incorrect Exif variable used in longitude calculation
Note: See TracChangeset
for help on using the changeset viewer.