diff --git a/lib/ActivityShortcode.class.php b/lib/ActivityShortcode.class.php index 92289db..a43382d 100644 --- a/lib/ActivityShortcode.class.php +++ b/lib/ActivityShortcode.class.php @@ -10,7 +10,7 @@ public static function init() { } // Shortcode handler function - // [ride id=id som=metric map_width="100%" map_height="400px"] + // [ride id=id som=metric map_width="100%" map_height="400px" markers=false] public static function handler( $atts ) { self::$add_script = true; @@ -20,6 +20,7 @@ public static function handler( $atts ) { 'map_width' => '480', 'map_height' => '320', 'athlete_token' => WPStrava::get_instance()->settings->get_default_token(), + 'markers' => false, ); extract( shortcode_atts( $defaults, $atts ) ); @@ -67,7 +68,7 @@ public static function handler( $atts ) { ' . - WPStrava_StaticMap::get_image_tag( $ride_details, $map_height, $map_width ) . + WPStrava_StaticMap::get_image_tag( $ride_details, $map_height, $map_width, $markers ) . ''; } // End if( $ride_details ). } // handler diff --git a/lib/Polyline.php b/lib/Polyline.php new file mode 100755 index 0000000..692e128 --- /dev/null +++ b/lib/Polyline.php @@ -0,0 +1,152 @@ +. + * + * @category Mapping + * @package Polyline + * @author E. McConville + * @copyright 2009-2015 E. McConville + * @license http://www.gnu.org/licenses/lgpl.html LGPL v3 + * @version GIT: $Id: db01b3fea5d96533da928252135ac8f247c1b250 $ + * @link https://github.com/emcconville/google-map-polyline-encoding-tool + */ + +/** + * Polyline encoding & decoding class + * + * Convert list of points to encoded string following Google's Polyline + * Algorithm. + * + * @category Mapping + * @package Polyline + * @author E. McConville + * @license http://www.gnu.org/licenses/lgpl.html LGPL v3 + * @link https://github.com/emcconville/google-map-polyline-encoding-tool + */ +class Polyline +{ + /** + * Default precision level of 1e-5. + * + * Overwrite this property in extended class to adjust precision of numbers. + * !!!CAUTION!!! + * 1) Adjusting this value will not guarantee that third party + * libraries will understand the change. + * 2) Float point arithmetic IS NOT real number arithmetic. PHP's internal + * float precision may contribute to undesired rounding. + * + * @var int $precision + */ + protected static $precision = 5; + + /** + * Apply Google Polyline algorithm to list of points. + * + * @param array $points List of points to encode. Can be a list of tuples, + * or a flat on dimensional array. + * + * @return string encoded string + */ + final public static function encode( $points ) + { + $points = self::flatten($points); + $encodedString = ''; + $index = 0; + $previous = array(0,0); + foreach ( $points as $number ) { + $number = (float)($number); + $number = (int)round($number * pow(10, static::$precision)); + $diff = $number - $previous[$index % 2]; + $previous[$index % 2] = $number; + $number = $diff; + $index++; + $number = ($number < 0) ? ~($number << 1) : ($number << 1); + $chunk = ''; + while ( $number >= 0x20 ) { + $chunk .= chr((0x20 | ($number & 0x1f)) + 63); + $number >>= 5; + } + $chunk .= chr($number + 63); + $encodedString .= $chunk; + } + return $encodedString; + } + + /** + * Reverse Google Polyline algorithm on encoded string. + * + * @param string $string Encoded string to extract points from. + * + * @return array points + */ + final public static function decode( $string ) + { + $points = array(); + $index = $i = 0; + $previous = array(0,0); + while ($i < strlen($string)) { + $shift = $result = 0x00; + do { + $bit = ord(substr($string, $i++)) - 63; + $result |= ($bit & 0x1f) << $shift; + $shift += 5; + } while ($bit >= 0x20); + + $diff = ($result & 1) ? ~($result >> 1) : ($result >> 1); + $number = $previous[$index % 2] + $diff; + $previous[$index % 2] = $number; + $index++; + $points[] = $number * 1 / pow(10, static::$precision); + } + return $points; + } + + /** + * Reduce multi-dimensional to single list + * + * @param array $array Subject array to flatten. + * + * @return array flattened + */ + final public static function flatten( $array ) + { + $flatten = array(); + array_walk_recursive( + $array, // @codeCoverageIgnore + function ($current) use (&$flatten) { + $flatten[] = $current; + } + ); + return $flatten; + } + + /** + * Concat list into pairs of points + * + * @param array $list One-dimensional array to segment into list of tuples. + * + * @return array pairs + */ + final public static function pair( $list ) + { + return is_array($list) ? array_chunk($list, 2) : array(); + } +} diff --git a/lib/RouteShortcode.class.php b/lib/RouteShortcode.class.php new file mode 100644 index 0000000..cd5667c --- /dev/null +++ b/lib/RouteShortcode.class.php @@ -0,0 +1,77 @@ + 0, + 'som' => WPStrava::get_instance()->settings->som, + 'map_width' => '480', + 'map_height' => '320', + 'athlete_token' => WPStrava::get_instance()->settings->get_default_token(), + 'markers' => false, + ); + + extract( shortcode_atts( $defaults, $atts ) ); + + $strava_som = WPStrava_SOM::get_som( $som ); + $route = WPStrava::get_instance()->routes; + $route_details = $route->getRoute( $id ); + + //sanitize width & height + $map_width = str_replace( '%', '', $map_width ); + $map_height = str_replace( '%', '', $map_height ); + $map_width = str_replace( 'px', '', $map_width ); + $map_height = str_replace( 'px', '', $map_height ); + + if ( $route_details ) { + return ' +
+ + + + + + + + + + + + + + + + + + + + +
' . __( 'Est. Moving Time', 'wp-strava' ) . '' . __( 'Distance', 'wp-strava' ) . '' . __( 'Elevation Gain', 'wp-strava' ) . '
' . $strava_som->time( $route_details->estimated_moving_time ) . '' . $strava_som->distance( $route_details->distance ) . '' . $strava_som->elevation( $route_details->elevation_gain ) . '
' . $strava_som->get_time_label() . '' . $strava_som->get_distance_label() . '' . $strava_som->get_elevation_label() . '
' . + WPStrava_StaticMap::get_image_tag( $route_details, $map_height, $map_width, $markers ) . + '
'; + } // End if( $route_details ). + } // handler + + public static function print_scripts() { + if ( self::$add_script ) { + wp_enqueue_style( 'wp-strava-style' ); + + //wp_print_scripts('google-maps'); + //wp_print_scripts('wp-strava-script'); + } + } +} + +// Initialize short code +WPStrava_RouteShortcode::init(); diff --git a/lib/Routes.class.php b/lib/Routes.class.php new file mode 100644 index 0000000..fd2f664 --- /dev/null +++ b/lib/Routes.class.php @@ -0,0 +1,20 @@ +get_api()->get( "routes/{$route_id}" ); + } // getRouteDetails +} \ No newline at end of file diff --git a/lib/StaticMap.class.php b/lib/StaticMap.class.php index 38a9e29..b213f15 100644 --- a/lib/StaticMap.class.php +++ b/lib/StaticMap.class.php @@ -1,5 +1,7 @@ settings->gmaps_key; // Short circuit if missing key or ride object doesn't have the data we need. @@ -27,11 +30,28 @@ public static function get_image_tag( $ride, $height = 320, $width = 480 ) { if ( ! empty( $ride->map->polyline ) && ( $url_len + strlen( $ride->map->polyline ) < $max_chars ) ) { $url .= $ride->map->polyline; + $points = self::decode_polyline($ride->map->polyline); } elseif ( ! empty( $ride->map->summary_polyline ) ) { $url .= $ride->map->summary_polyline; + $points = self::decode_polyline($ride->map->summary_polyline); } + if ($markers) { + $markers = '&markers=color:green|' . $points['start'][0] . ',' . $points['start'][1] . + '&markers=color:red|' . $points['finish'][0] . ',' . $points['finish'][1]; + $url .= $markers; + } + return ""; } + private static function decode_polyline($enc) { + $points = Polyline::decode($enc); + $points = Polyline::pair($points); + $start = $points[0]; + $finish = $points[count($points)-1]; + + return array('start' => $start, 'finish' => $finish); + } + } diff --git a/lib/Strava.class.php b/lib/Strava.class.php index 375f751..79b1ff2 100644 --- a/lib/Strava.class.php +++ b/lib/Strava.class.php @@ -5,6 +5,7 @@ require_once WPSTRAVA_PLUGIN_DIR . 'lib/LatestRidesWidget.class.php'; require_once WPSTRAVA_PLUGIN_DIR . 'lib/LatestMapWidget.class.php'; require_once WPSTRAVA_PLUGIN_DIR . 'lib/ActivityShortcode.class.php'; +require_once WPSTRAVA_PLUGIN_DIR . 'lib/RouteShortcode.class.php'; require_once WPSTRAVA_PLUGIN_DIR . 'lib/StaticMap.class.php'; class WPStrava { @@ -13,6 +14,7 @@ class WPStrava { private $settings = null; private $api = array(); // Holds an array of APIs. private $rides = null; + private $routes = null; private function __construct() { $this->settings = new WPStrava_Settings(); @@ -40,7 +42,9 @@ public function __get( $name ) { // On-demand classes. if ( $name == 'rides' ) { return $this->get_rides(); - } + } elseif ( $name == 'routes' ) { + return $this->get_routes(); + } if ( isset( $this->{$name} ) ) { return $this->{$name}; @@ -71,6 +75,14 @@ public function get_rides() { return $this->rides; } + public function get_routes() { + if ( ! $this->routes ) { + require_once WPSTRAVA_PLUGIN_DIR . 'lib/Routes.class.php'; + $this->routes = new WPStrava_Routes(); + } + return $this->routes; + } + public function register_scripts() { // Register a personalized stylesheet wp_register_style( 'wp-strava-style', WPSTRAVA_PLUGIN_URL . 'css/wp-strava.css' ); diff --git a/readme.txt b/readme.txt index 9b553a5..b58a9c8 100755 --- a/readme.txt +++ b/readme.txt @@ -22,9 +22,14 @@ Also takes the following optional parameters: * map_width - width (width of image in pixels). * map_height - height (height of image in pixels). * athlete_token - specify a different athlete (you can copy this value from https://www.strava.com/settings/api or the wp-strava settings page at /wp-admin/options-general.php?page=wp-strava-options). +* markers - Display markers at the start/finish point (true/false, defaults to false). [ride] is an alias for [activity] and will accept the same parameters (kept for backwards compatibility). +[route id=NUMBER] - add to any page or post. Shows a summary of the activity plus a map if a google maps key has been added. + +This also takes the same optional parameters as the activity shortcode above. + = Widgets = Strava Latest Activity List - shows a list of the last few activities.