Changeset 1566
- Timestamp:
- 05/12/2015 10:41:20 PM (10 years ago)
- Location:
- sites/trunk/wordcamp.org/public_html/wp-content/themes/wordcamp-central-2012
- Files:
-
- 4 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordcamp.org/public_html/wp-content/themes/wordcamp-central-2012/functions.php
r1545 r1566 44 44 add_filter( 'wp_nav_menu_items', array( __CLASS__, 'add_rss_links_to_footer_menu' ), 10, 2 ); 45 45 46 add_shortcode( 'wcc_map', array( __CLASS__, 'shortcode_map' ) ); 46 47 add_shortcode( 'wcc_about_stats', array( __CLASS__, 'shortcode_about_stats' ) ); 47 48 } … … 184 185 */ 185 186 static function enqueue_scripts() { 186 wp_enqueue_style( 'central', get_stylesheet_uri(), array(), 5);187 wp_enqueue_script( 'wordcamp-central', get_stylesheet_directory_uri() . '/js/central.js', array( 'jquery', 'underscore' ), 1, true );188 189 wp_localize_script( 'wordcamp-central', 'wordcampCentralOptions', array( 'ajaxURL' => admin_url( 'admin-ajax.php' )) );187 wp_enqueue_style( 'central', get_stylesheet_uri(), array(), 6 ); 188 wp_enqueue_script( 'wordcamp-central', get_stylesheet_directory_uri() . '/js/central.js', array( 'jquery', 'underscore' ), 2, true ); 189 190 wp_localize_script( 'wordcamp-central', 'wordcampCentralOptions', self::get_javascript_options() ); 190 191 191 192 /* We add some JavaScript to pages with the comment form … … 200 201 } 201 202 203 if ( is_page( 'about' ) || is_page( 'schedule' ) ) { 204 wp_enqueue_script( 'google-maps', 'https://maps.googleapis.com/maps/api/js', array(), false, true ); 205 } 206 } 207 208 /** 209 * Build the array of options to pass to the client side 210 * 211 * @return array 212 */ 213 protected static function get_javascript_options() { 214 global $post; 215 216 $options = array( 'ajaxURL' => admin_url( 'admin-ajax.php' ) ); 217 218 if ( $map_id = self::get_map_id( $post->post_content ) ) { 219 $options['mapContainer'] = "wcc-map-$map_id"; 220 $options['markerIconBaseURL'] = get_stylesheet_directory_uri() . '/images/'; 221 $options['markerClusterIcon'] = 'icon-marker-clustered.png'; 222 $options['markerIconAnchorXOffset'] = 24; 223 $options['markerIconHeight'] = 94; 224 $options['markerIconWidth'] = 122; 225 226 if ( $map_markers = self::get_map_markers( $map_id ) ) { 227 $options['mapMarkers'] = $map_markers; 228 } 229 } 230 231 return $options; 232 } 233 234 /** 235 * Get the ID of the map called in the given page 236 * 237 * @param string $post_content 238 * 239 * @return mixed A string of the map name on success, or false on failure 240 */ 241 protected static function get_map_id( $post_content ) { 242 $map_id = false; 243 244 if ( has_shortcode( $post_content, 'wcc_map' ) ) { 245 preg_match_all( '/' . get_shortcode_regex() . '/s', $post_content, $shortcodes, PREG_SET_ORDER ); 246 247 foreach ( $shortcodes as $shortcode ) { 248 if ( 'wcc_map' == $shortcode[2] ) { 249 $attributes = shortcode_parse_atts( $shortcode[3] ); 250 $map_id = sanitize_text_field( $attributes['id'] ); 251 break; 252 } 253 } 254 } 255 256 return $map_id; 257 } 258 259 /** 260 * Get the markers assigned to the given map 261 * 262 * @param string $map_id 263 * 264 * @return array 265 */ 266 protected static function get_map_markers( $map_id ) { 267 $transient_key = "wcc_map_markers_$map_id"; 268 269 if ( $markers = get_transient( $transient_key ) ) { 270 return $markers; 271 } else { 272 $markers = array(); 273 } 274 275 // Get the raw marker posts for the given map 276 $parameters = array( 277 'post_type' => 'wordcamp', 278 'posts_per_page' => -1, 279 ); 280 281 switch( $map_id ) { 282 case 'schedule': 283 $parameters['post_status'][] = array( 'publish', 'pending' ); 284 $parameters['meta_query'][] = array( 285 'key' => 'Start Date (YYYY-mm-dd)', 286 'value' => strtotime( '-2 days' ), 287 'compare' => '>', 288 ); 289 break; 290 } 291 292 $raw_markers = get_posts( $parameters ); 293 294 // Convert the raw markers into prepared objects that are ready to be used on the JavaScript side 295 foreach ( $raw_markers as $marker ) { 296 if ( 'schedule' == $map_id ) { 297 $marker_type = 'upcoming'; 298 } else { 299 $marker_type = get_post_meta( $marker->ID, 'Start Date (YYYY-mm-dd)', true ) > strtotime( '-2 days' ) ? 'upcoming' : 'past'; 300 } 301 302 if ( ! $coordinates = get_post_meta( $marker->ID, '_venue_coordinates', true ) ) { 303 continue; 304 } 305 306 $markers[ $marker->ID ] = array( 307 'id' => $marker->ID, 308 'name' => wcpt_get_wordcamp_title( $marker->ID ), 309 'dates' => wcpt_get_wordcamp_start_date( $marker->ID ), 310 'location' => get_post_meta( $marker->ID, 'Location', true ), 311 'venueName' => get_post_meta( $marker->ID, 'Venue Name', true ), 312 'url' => self::get_best_wordcamp_url( $marker->ID ), 313 'latitude' => $coordinates['latitude'], 314 'longitude' => $coordinates['longitude'], 315 'iconURL' => "icon-marker-{$marker_type}-2x.png", 316 ); 317 } 318 319 $markers = apply_filters( 'wcc_get_map_markers', $markers ); 320 321 set_transient( $transient_key, $markers, WEEK_IN_SECONDS ); 322 323 return $markers; 202 324 } 203 325 … … 649 771 650 772 /** 773 * Render the [wcc_map] shortcode 774 * 775 * @param array $attributes 776 * 777 * @return string 778 */ 779 public static function shortcode_map( $attributes ) { 780 $attributes = shortcode_atts( array( 'id' => '' ), $attributes ); 781 782 ob_start(); 783 require( __DIR__ . '/shortcode-about-map.php' ); 784 return ob_get_clean(); 785 } 786 787 /** 651 788 * Render the [wcc_about_stats] shortcode 652 789 * -
sites/trunk/wordcamp.org/public_html/wp-content/themes/wordcamp-central-2012/js/central.js
r1405 r1566 1 /** 2 * @name MarkerClusterer for Google Maps v3 3 * @version version 1.0 4 * @author Luke Mahe 5 * 6 * The library creates and manages per-zoom-level clusters for large amounts of 7 * markers. 8 */ 9 (function(){var d=null;function e(a){return function(b){this[a]=b}}function h(a){return function(){return this[a]}}var j; 10 function k(a,b,c){this.extend(k,google.maps.OverlayView);this.c=a;this.a=[];this.f=[];this.ca=[53,56,66,78,90];this.j=[];this.A=!1;c=c||{};this.g=c.gridSize||60;this.l=c.minimumClusterSize||2;this.J=c.maxZoom||d;this.j=c.styles||[];this.X=c.imagePath||this.Q;this.W=c.imageExtension||this.P;this.O=!0;if(c.zoomOnClick!=void 0)this.O=c.zoomOnClick;this.r=!1;if(c.averageCenter!=void 0)this.r=c.averageCenter;l(this);this.setMap(a);this.K=this.c.getZoom();var f=this;google.maps.event.addListener(this.c, 11 "zoom_changed",function(){var a=f.c.getZoom();if(f.K!=a)f.K=a,f.m()});google.maps.event.addListener(this.c,"idle",function(){f.i()});b&&b.length&&this.C(b,!1)}j=k.prototype;j.Q="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/images/m";j.P="png";j.extend=function(a,b){return function(a){for(var b in a.prototype)this.prototype[b]=a.prototype[b];return this}.apply(a,[b])};j.onAdd=function(){if(!this.A)this.A=!0,n(this)};j.draw=function(){}; 12 function l(a){if(!a.j.length)for(var b=0,c;c=a.ca[b];b++)a.j.push({url:a.X+(b+1)+"."+a.W,height:c,width:c})}j.S=function(){for(var a=this.o(),b=new google.maps.LatLngBounds,c=0,f;f=a[c];c++)b.extend(f.getPosition());this.c.fitBounds(b)};j.z=h("j");j.o=h("a");j.V=function(){return this.a.length};j.ba=e("J");j.I=h("J");j.G=function(a,b){for(var c=0,f=a.length,g=f;g!==0;)g=parseInt(g/10,10),c++;c=Math.min(c,b);return{text:f,index:c}};j.$=e("G");j.H=h("G"); 13 j.C=function(a,b){for(var c=0,f;f=a[c];c++)q(this,f);b||this.i()};function q(a,b){b.s=!1;b.draggable&&google.maps.event.addListener(b,"dragend",function(){b.s=!1;a.L()});a.a.push(b)}j.q=function(a,b){q(this,a);b||this.i()};function r(a,b){var c=-1;if(a.a.indexOf)c=a.a.indexOf(b);else for(var f=0,g;g=a.a[f];f++)if(g==b){c=f;break}if(c==-1)return!1;b.setMap(d);a.a.splice(c,1);return!0}j.Y=function(a,b){var c=r(this,a);return!b&&c?(this.m(),this.i(),!0):!1}; 14 j.Z=function(a,b){for(var c=!1,f=0,g;g=a[f];f++)g=r(this,g),c=c||g;if(!b&&c)return this.m(),this.i(),!0};j.U=function(){return this.f.length};j.getMap=h("c");j.setMap=e("c");j.w=h("g");j.aa=e("g"); 15 j.v=function(a){var b=this.getProjection(),c=new google.maps.LatLng(a.getNorthEast().lat(),a.getNorthEast().lng()),f=new google.maps.LatLng(a.getSouthWest().lat(),a.getSouthWest().lng()),c=b.fromLatLngToDivPixel(c);c.x+=this.g;c.y-=this.g;f=b.fromLatLngToDivPixel(f);f.x-=this.g;f.y+=this.g;c=b.fromDivPixelToLatLng(c);b=b.fromDivPixelToLatLng(f);a.extend(c);a.extend(b);return a};j.R=function(){this.m(!0);this.a=[]}; 16 j.m=function(a){for(var b=0,c;c=this.f[b];b++)c.remove();for(b=0;c=this.a[b];b++)c.s=!1,a&&c.setMap(d);this.f=[]};j.L=function(){var a=this.f.slice();this.f.length=0;this.m();this.i();window.setTimeout(function(){for(var b=0,c;c=a[b];b++)c.remove()},0)};j.i=function(){n(this)}; 17 function n(a){if(a.A)for(var b=a.v(new google.maps.LatLngBounds(a.c.getBounds().getSouthWest(),a.c.getBounds().getNorthEast())),c=0,f;f=a.a[c];c++)if(!f.s&&b.contains(f.getPosition())){for(var g=a,u=4E4,o=d,v=0,m=void 0;m=g.f[v];v++){var i=m.getCenter();if(i){var p=f.getPosition();if(!i||!p)i=0;else var w=(p.lat()-i.lat())*Math.PI/180,x=(p.lng()-i.lng())*Math.PI/180,i=Math.sin(w/2)*Math.sin(w/2)+Math.cos(i.lat()*Math.PI/180)*Math.cos(p.lat()*Math.PI/180)*Math.sin(x/2)*Math.sin(x/2),i=6371*2*Math.atan2(Math.sqrt(i), 18 Math.sqrt(1-i));i<u&&(u=i,o=m)}}o&&o.F.contains(f.getPosition())?o.q(f):(m=new s(g),m.q(f),g.f.push(m))}}function s(a){this.k=a;this.c=a.getMap();this.g=a.w();this.l=a.l;this.r=a.r;this.d=d;this.a=[];this.F=d;this.n=new t(this,a.z(),a.w())}j=s.prototype; 19 j.q=function(a){var b;a:if(this.a.indexOf)b=this.a.indexOf(a)!=-1;else{b=0;for(var c;c=this.a[b];b++)if(c==a){b=!0;break a}b=!1}if(b)return!1;if(this.d){if(this.r)c=this.a.length+1,b=(this.d.lat()*(c-1)+a.getPosition().lat())/c,c=(this.d.lng()*(c-1)+a.getPosition().lng())/c,this.d=new google.maps.LatLng(b,c),y(this)}else this.d=a.getPosition(),y(this);a.s=!0;this.a.push(a);b=this.a.length;b<this.l&&a.getMap()!=this.c&&a.setMap(this.c);if(b==this.l)for(c=0;c<b;c++)this.a[c].setMap(d);b>=this.l&&a.setMap(d); 20 a=this.c.getZoom();if((b=this.k.I())&&a>b)for(a=0;b=this.a[a];a++)b.setMap(this.c);else if(this.a.length<this.l)z(this.n);else{b=this.k.H()(this.a,this.k.z().length);this.n.setCenter(this.d);a=this.n;a.B=b;a.ga=b.text;a.ea=b.index;if(a.b)a.b.innerHTML=b.text;b=Math.max(0,a.B.index-1);b=Math.min(a.j.length-1,b);b=a.j[b];a.da=b.url;a.h=b.height;a.p=b.width;a.M=b.textColor;a.e=b.anchor;a.N=b.textSize;a.D=b.backgroundPosition;this.n.show()}return!0}; 21 j.getBounds=function(){for(var a=new google.maps.LatLngBounds(this.d,this.d),b=this.o(),c=0,f;f=b[c];c++)a.extend(f.getPosition());return a};j.remove=function(){this.n.remove();this.a.length=0;delete this.a};j.T=function(){return this.a.length};j.o=h("a");j.getCenter=h("d");function y(a){a.F=a.k.v(new google.maps.LatLngBounds(a.d,a.d))}j.getMap=h("c"); 22 function t(a,b,c){a.k.extend(t,google.maps.OverlayView);this.j=b;this.fa=c||0;this.u=a;this.d=d;this.c=a.getMap();this.B=this.b=d;this.t=!1;this.setMap(this.c)}j=t.prototype; 23 j.onAdd=function(){this.b=document.createElement("DIV");if(this.t)this.b.style.cssText=A(this,B(this,this.d)),this.b.innerHTML=this.B.text;this.getPanes().overlayMouseTarget.appendChild(this.b);var a=this;google.maps.event.addDomListener(this.b,"click",function(){var b=a.u.k;google.maps.event.trigger(b,"clusterclick",a.u);b.O&&a.c.fitBounds(a.u.getBounds())})};function B(a,b){var c=a.getProjection().fromLatLngToDivPixel(b);c.x-=parseInt(a.p/2,10);c.y-=parseInt(a.h/2,10);return c} 24 j.draw=function(){if(this.t){var a=B(this,this.d);this.b.style.top=a.y+"px";this.b.style.left=a.x+"px"}};function z(a){if(a.b)a.b.style.display="none";a.t=!1}j.show=function(){if(this.b)this.b.style.cssText=A(this,B(this,this.d)),this.b.style.display="";this.t=!0};j.remove=function(){this.setMap(d)};j.onRemove=function(){if(this.b&&this.b.parentNode)z(this),this.b.parentNode.removeChild(this.b),this.b=d};j.setCenter=e("d"); 25 function A(a,b){var c=[];c.push("background-image:url("+a.da+");");c.push("background-position:"+(a.D?a.D:"0 0")+";");typeof a.e==="object"?(typeof a.e[0]==="number"&&a.e[0]>0&&a.e[0]<a.h?c.push("height:"+(a.h-a.e[0])+"px; padding-top:"+a.e[0]+"px;"):c.push("height:"+a.h+"px; line-height:"+a.h+"px;"),typeof a.e[1]==="number"&&a.e[1]>0&&a.e[1]<a.p?c.push("width:"+(a.p-a.e[1])+"px; padding-left:"+a.e[1]+"px;"):c.push("width:"+a.p+"px; text-align:center;")):c.push("height:"+a.h+"px; line-height:"+a.h+ 26 "px; width:"+a.p+"px; text-align:center;");c.push("cursor:pointer; top:"+b.y+"px; left:"+b.x+"px; color:"+(a.M?a.M:"black")+"; position:absolute; font-size:"+(a.N?a.N:11)+"px; font-family:Arial,sans-serif; font-weight:bold");return c.join("")}window.MarkerClusterer=k;k.prototype.addMarker=k.prototype.q;k.prototype.addMarkers=k.prototype.C;k.prototype.clearMarkers=k.prototype.R;k.prototype.fitMapToMarkers=k.prototype.S;k.prototype.getCalculator=k.prototype.H;k.prototype.getGridSize=k.prototype.w; 27 k.prototype.getExtendedBounds=k.prototype.v;k.prototype.getMap=k.prototype.getMap;k.prototype.getMarkers=k.prototype.o;k.prototype.getMaxZoom=k.prototype.I;k.prototype.getStyles=k.prototype.z;k.prototype.getTotalClusters=k.prototype.U;k.prototype.getTotalMarkers=k.prototype.V;k.prototype.redraw=k.prototype.i;k.prototype.removeMarker=k.prototype.Y;k.prototype.removeMarkers=k.prototype.Z;k.prototype.resetViewport=k.prototype.m;k.prototype.repaint=k.prototype.L;k.prototype.setCalculator=k.prototype.$; 28 k.prototype.setGridSize=k.prototype.aa;k.prototype.setMaxZoom=k.prototype.ba;k.prototype.onAdd=k.prototype.onAdd;k.prototype.draw=k.prototype.draw;s.prototype.getCenter=s.prototype.getCenter;s.prototype.getSize=s.prototype.T;s.prototype.getMarkers=s.prototype.o;t.prototype.onAdd=t.prototype.onAdd;t.prototype.draw=t.prototype.draw;t.prototype.onRemove=t.prototype.onRemove; 29 })(); 30 31 32 /** 33 * WordCampCentral 34 * 35 * Custom client-side behaviors for the Central theme 36 */ 1 37 var WordCampCentral = ( function( $ ) { 2 3 38 // templateOptions is copied from Core in order to avoid an extra HTTP request just to get wp.template 4 39 var options, … … 11 46 /** 12 47 * Initialization that runs as soon as this file has loaded 48 * 49 * @param {object} initOptions 13 50 */ 14 51 function immediateInit( initOptions ) { … … 23 60 */ 24 61 function documentReadyInit() { 62 try { 63 if ( options.hasOwnProperty( 'mapContainer' ) && options.hasOwnProperty( 'mapMarkers' ) ) { 64 loadMap( options.mapContainer, options.mapMarkers ); 65 } 66 } catch ( exception ) { 67 log( exception ); 68 } 25 69 } 26 70 … … 104 148 } 105 149 150 /** 151 * Build a Google Map in the given container with the given marker data 152 * 153 * @param {string} container 154 * @param {object} markers 155 */ 156 function loadMap( container, markers ) { 157 if ( ! $( '#' + container ).length ) { 158 throw "Map container element isn't present in the DOM."; 159 } 160 161 if ( 'undefined' === typeof( google ) || ! google.hasOwnProperty( 'maps' ) ) { 162 throw 'Google Maps library is not loaded.'; 163 } 164 165 var map, markerCluster, 166 mapOptions = { 167 center : new google.maps.LatLng( 15.000, 7.000 ), 168 zoom : 2, 169 zoomControl : true, 170 mapTypeControl : false, 171 streetViewControl : false 172 }; 173 174 map = new google.maps.Map( document.getElementById( container ), mapOptions ); 175 markers = createMarkers( map, markers ); 176 177 /* 178 * The About map contains all camps, past and present, so there will be camps from different years that 179 * are located in the same venue, and their markers will overlap. 180 */ 181 if ( 'wcc-map-about' == container ) { 182 markers = repositionOverlappingMarkers( markers ); 183 } 184 185 markerCluster = clusterMarkers( map, markers ); 186 } 187 188 /** 189 * Create markers on a map with the given marker data 190 * 191 * Normally the markers would be assigned to the map at this point, but we'll run them through MarkerClusterer 192 * later on, so adding them to the map now is unnecessary and negatively affects performance. 193 * 194 * @param {google.maps.Map} map 195 * @param {object} markers 196 * 197 * @return {object} 198 */ 199 function createMarkers( map, markers ) { 200 var markerID, 201 infoWindowTemplate = _.template( $( '#tmpl-wcc-map-marker' ).html(), null, templateOptions ), 202 infoWindow = new google.maps.InfoWindow( { 203 pixelOffset: new google.maps.Size( -options.markerIconAnchorXOffset, 0 ) 204 } ); 205 206 for ( markerID in markers ) { 207 if ( ! markers.hasOwnProperty( markerID ) ) { 208 continue; 209 } 210 211 markers[ markerID ] = new google.maps.Marker( { 212 wccID : markerID, 213 wccURL : markers[ markerID ].url, 214 wccDates : markers[ markerID ].dates, 215 location : markers[ markerID ].location, 216 venueName : markers[ markerID ].venueName, 217 title : markers[ markerID ].name, 218 219 icon : { 220 url : options.markerIconBaseURL + markers[ markerID ].iconURL, 221 size : new google.maps.Size( options.markerIconHeight, options.markerIconWidth ), 222 anchor : new google.maps.Point( options.markerIconAnchorXOffset, options.markerIconWidth / 2 ), 223 scaledSize : new google.maps.Size( options.markerIconHeight / 2, options.markerIconWidth / 2 ) 224 }, 225 226 position : new google.maps.LatLng( 227 markers[ markerID ].latitude, 228 markers[ markerID ].longitude 229 ) 230 } ); 231 232 google.maps.event.addListener( markers[ markerID ], 'click', function() { 233 try { 234 infoWindow.setContent( infoWindowTemplate( { wordcamp: markers[ this.wccID ] } ) ); 235 infoWindow.open( map, markers[ this.wccID ] ); 236 } catch ( exception ) { 237 log( exception ); 238 } 239 } ); 240 } 241 242 return markers; 243 } 244 245 /** 246 * Offset the position of overlapping markers 247 * 248 * Often camps will use the same venue for multiple years, and those map pins would be placed in the exact same 249 * spot by default, making it impossible to open the overlaid pins, or even know that they're there. This 250 * function will spread overlapping pins out in a circle around the original point. 251 * 252 * @todo It'd be nice to adjust the distance on the fly based on the zoom level, so that you could always see 253 * that there are multiple markers at a given location, rather than having to zoom in to the neighborhood 254 * level to know that. 255 * 256 * @param {object} markers 257 * 258 * @returns {object} 259 */ 260 function repositionOverlappingMarkers( markers ) { 261 var groupedMarkers = groupMarkersByCoordinates( markers ); 262 263 _.each( groupedMarkers, function( markerGroup ) { 264 var markerGroupSize = _.size( markerGroup ); 265 266 if ( markerGroupSize > 1 ) { 267 var currentMarkerIndex = 1, 268 distance = markerGroupSize == 2 ? .1 : .5; // when there are only 2 markers, it's not as obvious that they're centered around a point in the middle 269 270 _.each( markerGroup, function( marker, markerID ) { 271 var bearing = currentMarkerIndex / markerGroupSize * 360 + 90, 272 newPosition = calculateDestinationPoint( marker.getPosition(), bearing, distance ); 273 274 markers[ markerID ].setPosition( newPosition ); 275 currentMarkerIndex++; 276 } ); 277 } 278 } ); 279 280 return markers; 281 } 282 283 /** 284 * Group markers by their coordinates 285 * 286 * @param {object} markers 287 * 288 * @returns {object} 289 */ 290 function groupMarkersByCoordinates( markers ) { 291 var groupedMarkers = {}; 292 293 _.each( markers, function( marker, markerID ) { 294 var position = marker.getPosition(), 295 coordinates = position.lat() + '|' + position.lng(); 296 297 if ( ! groupedMarkers.hasOwnProperty( coordinates ) ) { 298 groupedMarkers[ coordinates ] = {}; 299 } 300 301 groupedMarkers[ coordinates ][ markerID ] = marker; 302 } ); 303 304 return groupedMarkers; 305 } 306 307 /** 308 * Calculate the destination point after moving a distance with a bearing from a starting point 309 * 310 * Based on http://www.movable-type.co.uk/scripts/latlong.html 311 * 312 * @param {google.maps.LatLng} startPosition 313 * @param {number} bearing in degrees 314 * @param {number} distance in kilometers 315 * 316 * @returns {google.maps.LatLng} 317 */ 318 function calculateDestinationPoint( startPosition, bearing, distance ) { 319 var startLatitude, startLongitude, newLatitude, newLongitude, 320 earthRadius = 6371; // in kilometers 321 322 startLatitude = startPosition.lat().toRadians(); 323 startLongitude = startPosition.lng().toRadians(); 324 bearing = bearing.toRadians(); 325 326 newLatitude = Math.asin( 327 Math.sin( startLatitude ) * 328 Math.cos( distance / earthRadius ) + 329 Math.cos( startLatitude ) * 330 Math.sin( distance / earthRadius ) * 331 Math.cos( bearing ) 332 ); 333 334 newLongitude = startLongitude + Math.atan2( 335 Math.sin( bearing ) * 336 Math.sin( distance / earthRadius ) * 337 Math.cos( startLatitude ), 338 339 Math.cos( distance / earthRadius ) - 340 Math.sin( startLatitude ) * 341 Math.sin( newLatitude ) 342 ); 343 344 return new google.maps.LatLng( newLatitude.toDegrees(), newLongitude.toDegrees() ); 345 } 346 347 /** 348 * Cluster the markers into groups for improved performance and UX 349 * 350 * options.markerClusterIcon is just 1x size, because MarkerClusterer doesn't support retina images. 351 * MarkerClusterer Plus does, but it doesn't seem as official, so I'm not as confident that it's secure, 352 * stable, etc. 353 * 354 * @todo the location of clustered pins is shifted off the center of where it should be when zoomed out, 355 * and shifts closer to the actual location each time you zoom in 356 * 357 * @param {google.maps.Map} map 358 * @param {object} markers 359 * 360 * @return MarkerClusterer 361 */ 362 function clusterMarkers( map, markers ) { 363 var clusterOptions, 364 markersArray = []; 365 366 /* 367 * We're storing markers in an object so that they can be accessed directly by ID, rather than having to 368 * loop through them to find one. MarkerClusterer requires them to be passed in as an object, though, so 369 * we need to convert them here. 370 */ 371 for ( var m in markers ) { 372 markersArray.push( markers[ m ] ); 373 } 374 375 clusterOptions = { 376 maxZoom: 13, 377 gridSize: 40, 378 styles: [ 379 { 380 url: options.markerIconBaseURL + options.markerClusterIcon, 381 height: options.markerIconWidth / 2, 382 width: options.markerIconHeight / 2, 383 anchor: [ 5, -0 ], 384 textColor: '#ffffff', 385 textSize: 22 386 }, 387 388 { 389 url: options.markerIconBaseURL + options.markerClusterIcon, 390 height: options.markerIconWidth / 2, 391 width: options.markerIconHeight / 2, 392 anchor: [ 5, -5 ], 393 textColor: '#ffffff', 394 textSize: 18 395 }, 396 397 { 398 url: options.markerIconBaseURL + options.markerClusterIcon, 399 height: options.markerIconWidth / 2, 400 width: options.markerIconHeight / 2, 401 anchor: [ 5, -5 ], 402 textColor: '#ffffff', 403 textSize: 18 404 } 405 ] 406 }; 407 408 return new MarkerClusterer( map, markersArray, clusterOptions ); 409 } 410 411 /** 412 * Log a message to the console 413 * 414 * @param {*} message 415 */ 416 function log( message ) { 417 if ( ! window.console ) { 418 return; 419 } 420 421 if ( 'string' == typeof( message ) ) { 422 console.log( 'WordCampCentral: ' + message ); 423 } else { 424 console.log( 'WordCampCentral: ', message ); 425 } 426 } 427 106 428 return { 107 429 immediateInit: immediateInit, … … 110 432 } )( jQuery ); 111 433 434 if ( 'undefined' === typeof( Number.prototype.toRadians ) ) { 435 /** 436 * Convert degrees to radians 437 * 438 * @returns {number} 439 */ 440 Number.prototype.toRadians = function() { 441 return this * Math.PI / 180; 442 }; 443 } 444 445 if ( 'undefined' === typeof( Number.prototype.toDegrees ) ) { 446 /** 447 * Convert radians to degrees 448 * 449 * @returns {number} 450 */ 451 Number.prototype.toDegrees = function() { 452 return this * 180 / Math.PI; 453 }; 454 } 455 112 456 WordCampCentral.immediateInit( wordcampCentralOptions ); 113 457 jQuery( document ).ready( WordCampCentral.documentReadyInit ); -
sites/trunk/wordcamp.org/public_html/wp-content/themes/wordcamp-central-2012/style.css
r1545 r1566 1966 1966 } 1967 1967 1968 .about-page .about-map {1969 float: left;1970 margin: -4px 20px 40px 0;1971 padding: 12px;1972 box-shadow: 0 1px 3px 1px rgba(0,0,0,.3);1973 -webkit-box-shadow: 0 1px 3px 1px rgba(0,0,0,.3);1974 }1975 1976 1968 #content .about-stats { 1977 1969 margin: 0; … … 2040 2032 display: inline-block; 2041 2033 margin-top: 5px; 2034 } 2035 2036 /* !03f. Maps */ 2037 /* ------------------------------------- */ 2038 2039 .wcc-map { 2040 position: relative; 2041 height: 325px; 2042 background-color: #E5E3DF; 2043 } 2044 2045 #wcc-map-spinner { 2046 position: absolute; 2047 float: none; 2048 top: 50%; 2049 left: 50%; 2050 margin: -10px 0 0 0; /* take half the height of the spinner off the top, so that it's perfectly centered */ 2051 } 2052 2053 .wcc-map-marker ul { 2054 margin-left: 0; 2055 } 2056 2057 .wcc-map-marker ul li { 2058 list-style-type: none; 2042 2059 } 2043 2060
Note: See TracChangeset
for help on using the changeset viewer.