/*
Copyright 2012-2021 VeloViewer. All Rights Reserved
###V77###
*/
var setSVPanoTimer = null,
    streetviewShown = false,
    svMap, svPano, fgSVPoly, bgSVPoly, hlSVPoly, marker, isPanningSV = false,
    svMarker,
    retinaImg = isRetinaDisplay() ? '@2x' : '',
    svTileSize = 256,
    mapProxy = https + '://',
    mapTileObjs, gMapMarkerArr = [],
    gMapMarkerArr2 = [],
    gMapFullGradArr = [],
    gmapMarkers = {},
    map3dDetailMult = 500,
    map3dsimplifyLimit = 600,
    mapDetailElevGradCount = 500,
    mapDetailPolylineCount = 100,
    gMapCurPosIcon = typeof(p3dpVs) === 'undefined' ? {
        path: google.maps.SymbolPath.CIRCLE,
        fillOpacity: 0,
        fillColor: '#000',
        strokeOpacity: 0.8,
        strokeColor: '#000',
        strokeWeight: 3,
        scale: 4 //pixels
    } : {
        path: google.maps.SymbolPath.CIRCLE,
        fillOpacity: 0,
        fillColor: '#000',
        strokeOpacity: 0.8,
        strokeColor: '#F00',
        strokeWeight: 6,
        scale: 10 //pixels
    },
    lm_ZwiftMapsMarker = typeof(getCookie('lm_ZwiftMapsMarker')) !== 'undefined' && +getCookie('lm_ZwiftMapsMarker') == 1;

var debug = false;
if (getParameterByName('debug') == '1') {
    debug = true;
}

if (typeof(getCookie('lm_rDistanceMarker')) === 'undefined') {
    setCookie('lm_rDistanceMarker', 0, 365);
}

function getBearing(x1, y1, x2, y2) {
    return Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
}

var gmapDetailPolylines = [];

function setMapDetail(type, parent) {
    if (type == 'G') {
        gmapDetailPolylines.forEach(function(d) {
            d.setMap(null);
        });
        gmapDetailPolylines = [];
    }
    var da = (typeof(segment.da) !== 'undefined' ? segment.da : (typeof(segment.distanceArr2Copy) !== 'undefined' ? segment.distanceArr2Copy : segment.distanceArr2));
    var lla = (typeof(segment.lla) !== 'undefined' ? segment.lla : (typeof(segment.latLngArr2Copy) !== 'undefined' ? segment.latLngArr2Copy : segment.latLngArr2)); //test
    if (typeof(bdsmel) === 'undefined') {
        var ea = (typeof(segment.ea) !== 'undefined' ? segment.ea : (typeof(segment.elevationArr2Copy) !== 'undefined' ? segment.elevationArr2Copy : segment.elevationArr2));
        bdsmel = filterData(da.map(function(d, i) {
            return {
                x: d,
                y: ea[i]
            }
        })).map(function(d) {
            return d.ySmooth
        });
    }

    var lData = bdsmel.map(function(d, i) {
        return {
            x: da[i],
            y: d,
            z: 0,
            i: i
        }
    });
    if (typeof(brushExtent) !== 'undefined' && brushExtent[0] != brushExtent[1] && brushExtent[1] > 0) {
        lData = lData.slice(filtIndExtent[0], filtIndExtent[1] + 1)
    }
    var mapDetailData = lData;
    var simpVal = 10;

    if (gMapFullGradArr.length == 0) {
        if (lData.length >= mapDetailElevGradCount) {
            mapDetailData = simplify(lData, simpVal, true);
            simpVal = simpVal / 2;
            while (mapDetailData.length < mapDetailElevGradCount && simpVal > 0.01) {
                mapDetailData = simplify(lData, simpVal, true);
                simpVal = simpVal / 2;
            }
        }

        gMapFullGradArr = mapDetailData.slice(1).map(function(d, i) {
			//console.log(i + ', ' + d.y + ', ' + mapDetailData[i].y + ', ' + d.x + ', ' + mapDetailData[i].x + ', ' + ((d.y - mapDetailData[i].y) / (d.x - mapDetailData[i].x)));
            return {
                c: colScale2((d.y - mapDetailData[i].y) / (d.x - mapDetailData[i].x)),
                x: d.x
            }
        });
    }

    if (lData.length >= mapDetailPolylineCount) {
        mapDetailData = simplify(lData, simpVal, true);
        simpVal = simpVal / 2;
        while (mapDetailData.length < mapDetailPolylineCount && simpVal > 0.01) {
            mapDetailData = simplify(lData, simpVal, true);
            simpVal = simpVal / 2;
        }
    }

    mapDetailData.forEach(function(d, i) {
        if (i > 0) {
            var lp = [];
            lla.slice(mapDetailData[i - 1].i, d.i + 1).forEach(function(d, i) {
                e = d;
                if (type == 'L') {
                    lp.push([d.lat, d.lng]);
                } else {
                    lp.push(new google.maps.LatLng(d.lat, d.lng));
                }
            });
            if (type == 'L') {
                //var ls = new OpenLayers.Geometry.LineString(lp);
                //var lv = new OpenLayers.Feature.Vector(ls, null, clone(mapLineFGBase));
                //lv.style.strokeColor = colScale2((mapDetailData[i].y - mapDetailData[i - 1].y) / (mapDetailData[i].x - mapDetailData[i - 1].x));
                var poly = new L.Polyline(lp, {
                    color: colScale2((mapDetailData[i].y - mapDetailData[i - 1].y) / (mapDetailData[i].x - mapDetailData[i - 1].x)),
                    opacity: 1,
                    weight: 2.5
                });
                parent.addLayer(poly);
            } else {
                var poly = new google.maps.Polyline({
                    path: lp,
                    strokeColor: colScale2((mapDetailData[i].y - mapDetailData[i - 1].y) / (mapDetailData[i].x - mapDetailData[i - 1].x)),
                    strokeOpacity: 1.0,
                    strokeWeight: 2,
                    zIndex: 100 + i
                });
                poly.setMap(parent);
                gmapDetailPolylines.push(poly);
            }
        }
    });
    if (typeof(p3dpPolylineClick) !== 'undefined') {
        p3dpPolylineClick()
    }
}

// VeloViewer's key, please get your own at thunderforest.com
var thunderforestKey = '3e8acaf16b3f4e36a80a1732e9e82c40';

mapTileObjs = [{
    key: 'veloviewer',
    name: 'VeloViewer',
    alt: 'Custom VeloViewer map',
    tile: function(coord, zoom) {
        return 'https://tile.thunderforest.com/veloviewer-oh4/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?apikey=' + thunderforestKey;
    }
}, {
    key: 'landscape',
    name: 'Landscape',
    alt: 'Landscape Map',
    tile: function(coord, zoom) {
        return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tile.thunderforest.com/landscape/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?apikey=' + thunderforestKey;
    }
}, {
    key: 'osm',
    name: 'Open Street',
    alt: 'Open Street Map',
    tile: function(coord, zoom) {
        return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tile.openstreetmap.org/' + zoom + '/' + coord.x + '/' + coord.y + '.png';
    }
}, {
    key: 'ocm',
    name: 'Open Cycle',
    alt: 'Open Cycle Map',
    tile: function(coord, zoom) {
        return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tile.thunderforest.com/cycle/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?apikey=' + thunderforestKey;
    }
}, {
    key: 'outdoors',
    name: 'Outdoors',
    alt: 'Outdoor Map',
    tile: function(coord, zoom) {
        return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tile.thunderforest.com/outdoors/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?apikey=' + thunderforestKey;
    }
}, {
    key: 'baw',
    name: 'Black & White',
    alt: 'Stamen Black and White map',
    tile: function(coord, zoom) {
        if (mapProxy.indexOf('https://') > -1) {
            return mapProxy + 'stamen-tiles-' + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.a.ssl.fastly.net/toner/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png';
        } else {
            return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tile.stamen.com/toner/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png';
        }
    }
}];

if (typeof(mbCustomToken) !== 'undefined' && mbCustomToken != '') {
    mapTileObjs = d3.merge([
        [{
            key: 'custom',
            name: 'Custom',
            alt: 'Your custom MapBox tiles',
            tile: function(coord, zoom) {
                if (mbCustomToken.substr(0, 5) == 'https') {
                    return mbCustomToken.replace('{y}', '{y}' + retinaImg).replace('{z}', zoom).replace('{x}', coord.x).replace('{y}', coord.y);
                } else {
                    return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tiles.mapbox.com/v4/' + mbCustomDomain + '/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?access_token=' + mbCustomToken;
                }
            }
        }], mapTileObjs
    ]);
}
/*if (typeof(mbLiveToken) !== 'undefined' && mbLiveToken != '') {
    mapTileObjs = d3.merge([
        [{
            key: 'live',
            name: 'Live',
            alt: 'VeloViewer Live Map',
            tile: function(coord, zoom) {
                return '/api/fileProxy.php?c=1&u=' + encodeURIComponent('https://api.mapbox.com/styles/v1/' + mbLiveDomain + '/tiles/256/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '?access_token=' + mbLiveToken);
            }
        }], mapTileObjs
    ]);
    if (typeof(mbLiveDomain2) !== 'undefined' && mbLiveDomain2 != '') {
        mapTileObjs = d3.merge([
            [{
                key: 'live2',
                name: 'Live 2',
                alt: 'VeloViewer Live Map V2',
                tile: function(coord, zoom) {
                    return '/api/fileProxy.php?c=1&u=' + encodeURIComponent('https://api.mapbox.com/styles/v1/' + mbLiveDomain2 + '/tiles/256/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '?access_token=' + mbLiveToken);
                }
            }], mapTileObjs
        ]);
    }
}*/

var z_london, z_watopia, z_newyork, z_richmond, z_innsbruck, z_yorkshire, z_critcity, z_france, z_italy, z_champs;

function zwiftMapsG(isShown) {
    if (typeof(activity) === 'undefined' && typeof(route) === 'undefined') return;
    var l_map = typeof(map) !== 'undefined' ? map : map3;
    if (typeof(z_london) === 'undefined') {
        z_london = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_London.jpg', {
            north: 51.5362,
            south: 51.4601,
            east: -0.0555,
            west: -0.1776
        });
        z_london.v_north = 51.5362;
        z_london.v_south = 51.4601;
        z_london.v_east = -0.0555;
        z_london.v_west = -0.1776;
        z_london.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_London.jpg';
        z_watopia = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Watopia_V2.jpg', {
            north: -11.62597,
            south: -11.70255,
            east: 167.03255,
            west: 166.87747
        });
        z_watopia.v_north = -11.62597;
        z_watopia.v_south = -11.70255;
        z_watopia.v_east = 167.03255;
        z_watopia.v_west = 166.87747;
        z_watopia.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Watopia_V2.jpg';
        z_newyork = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_NewYork.jpg', {
            north: 40.81725,
            south: 40.74085,
            east: -73.9222,
            west: -74.0227
        });
        z_newyork.v_north = 40.81725;
        z_newyork.v_south = 40.74085;
        z_newyork.v_east = -73.9222;
        z_newyork.v_west = -74.0227;
        z_newyork.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_NewYork.jpg';
        z_richmond = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Richmond.jpg', {
            north: 37.5774,
            south: 37.5014,
            east: -77.394,
            west: -77.48954
        });
        z_richmond.v_north = 37.5774;
        z_richmond.v_south = 37.5014;
        z_richmond.v_east = -77.394;
        z_richmond.v_west = -77.48954;
        z_richmond.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Richmond.jpg';
        z_innsbruck = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Innsbruck.jpg', {
            north: 47.2947,
            south: 47.2055,
            east: 11.4822,
            west: 11.3501
        });
        z_innsbruck.v_north = 47.2947;
        z_innsbruck.v_south = 47.2055;
        z_innsbruck.v_east = 11.4822;
        z_innsbruck.v_west = 11.3501;
        z_innsbruck.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Innsbruck.jpg';
        z_yorkshire = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Yorkshire.jpg', {
            north: 54.0254,
            south: 53.9491,
            east: -1.5022,
            west: -1.6320
        });
        z_yorkshire.v_north = 54.0254;
        z_yorkshire.v_south = 53.9491;
        z_yorkshire.v_east = -1.5022;
        z_yorkshire.v_west = -1.6320;
        z_yorkshire.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Yorkshire.jpg';
        z_critcity = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_CritCity.jpg', {
            north: -10.3657,
            south: -10.4038,
            east: 165.8207,
            west: 165.7824
        });
        z_critcity.v_north = -10.3657;
        z_critcity.v_south = -10.4038;
        z_critcity.v_east = 165.8207;
        z_critcity.v_west = 165.7824;
        z_critcity.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_CritCity.jpg';
        z_france = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_France.jpg', {
            north: -21.64155,
            south: -21.7564,
            east: 166.26125,
            west: 166.1384
        });
        z_france.v_north = -21.64155;
        z_france.v_south = -21.7564;
        z_france.v_east = 166.26125;
        z_france.v_west = 166.1384;
        z_france.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_France.jpg';
        z_italy = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Italy.jpg', {
            north: 44.5308037,
            south: 44.45463821,
            east: 11.36991729102076,
            west: 11.26261748
        });
        z_italy.v_north = 44.5308037;
        z_italy.v_south = 44.45463821;
        z_italy.v_east = 11.36991729102076;
        z_italy.v_west = 11.26261748;
        z_italy.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Italy.jpg';
        z_champs = new google.maps.GroundOverlay('https://cf.veloviewer.com/Zwift/MiniMap_Champs.jpg', {
            north: 48.9058,
            south: 48.82945,
            east: 2.3722,
            west: 2.2561
        });
        [, ],
        [, ]
        z_champs.v_north = 48.9058;
        z_champs.v_south = 48.82945;
        z_champs.v_east = 2.3722;
        z_champs.v_west = 2.2561;
        z_champs.v_url = 'https://cf.veloviewer.com/Zwift/MiniMap_Champs.jpg';

    }

    if (isShown) {
        z_london.setMap(svMap);
        z_watopia.setMap(svMap);
        z_newyork.setMap(svMap);
        z_richmond.setMap(svMap);
        z_innsbruck.setMap(svMap);
        z_yorkshire.setMap(svMap);
        z_critcity.setMap(svMap);
        z_france.setMap(svMap);
        z_italy.setMap(svMap);
        z_champs.setMap(svMap);
    } else {
        z_london.setMap(null);
        z_watopia.setMap(null);
        z_newyork.setMap(null);
        z_richmond.setMap(null);
        z_innsbruck.setMap(null);
        z_yorkshire.setMap(null);
        z_critcity.setMap(null);
        z_france.setMap(null);
        z_italy.setMap(null);
        z_champs.setMap(null);
    }
    d3.select('#svMapZwiftBtn').classed('active', lm_ZwiftMapsMarker);
    d3.select('#svMapZwiftBtn').style('background', lm_ZwiftMapsMarker ? 'rgb(187, 187, 187)' : '#fff');
}

function loadstreetview() {
    if (!streetviewShown) {

        d3.select('#svTab').style('margin', '-10px -10px 0px -10px').append('div')
            .attr({
                id: 'svMap',
                style: 'float:left;height:100%;width:100%;'
            });
        d3.select('#svTab').append('div')
            .attr({
                id: 'svPano',
                style: 'float:left;height:100%;width:0%;'
            });


        svMap = new google.maps.Map(document.getElementById('svMap'), {
            mapTypeControlOptions: {
                mapTypeIds: d3.merge([mapTileObjs.map(function(d) {
                    return d.key
                }), ['osuk', google.maps.MapTypeId.TERRAIN, google.maps.MapTypeId.SATELLITE, google.maps.MapTypeId.HYBRID]]),
                style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
            },
            mapTypeControl: true,
            fullscreenControl: true,
            scaleControl: true
        });

        mapTileObjs.forEach(function(d) {
            svMap.mapTypes.set(d.key, new google.maps.ImageMapType({
                getTileUrl: d.tile,
                tileSize: new google.maps.Size(256, 256),
                isPng: true,
                maxZoom: typeof(d.maxZoom) === 'undefined' ? 18 : d.maxZoom,
                minZoom: 1,
                name: d.name,
                alt: d.alt
            }));
        });

        svMap.mapTypes.set('osuk', new WarpedOsOpenSpaceMapType('CFA53F206D869053E0405F0ACA604903', document.location.href.replace(/http.*veloviewer\.com/, 'http://veloviewer.com'), svMap));

        if (typeof(segment.latLngArr2Copy) === 'undefined') {
            segment.latLngArr2Copy = segment.latLngArr2;
            segment.distanceArr2Copy = segment.distanceArr2;
        }
        var la = (typeof(llObj) !== 'undefined' ? llObj.data2 : segment.latLngArr2Copy);
        var da = (typeof(distObj) !== 'undefined' ? distObj.data : segment.distanceArr2Copy);

        var pos = new google.maps.LatLng(la[0].lat, la[0].lng);
        var bearing = getBearing(la[0].lat, la[0].lng, la[1].lat, la[1].lng);


        /*if (typeof(mbCustomToken) !== 'undefined' && mbCustomToken != '') {
            svMap.mapTypes.set('custom', new google.maps.ImageMapType({
                getTileUrl: function(coord, zoom) {
                    return mapProxy + ['a', 'b', 'c'][(coord.x + coord.y) % 3] + '.tiles.mapbox.com/v4/' + mbCustomDomain + '/' + zoom + '/' + coord.x + '/' + coord.y + retinaImg + '.png?access_token=' + mbCustomToken;
                },
                tileSize: new google.maps.Size(256, 256),
                name: 'Custom',
                maxZoom: 18
            }));
        }*/

        if (typeof(getCookie('lmap')) !== 'undefined' && d3.merge([mapTileObjs, ['osuk', 'terrain', 'hybrid', 'satellite']]).map(function(d) {
                return d.key ? d.key : d
            }).indexOf(getCookie('lmap')) > -1) {
            var lm = getCookie('lmap');
            if (lm == 'custom' && (typeof(mbCustomToken) === 'undefined' || mbCustomToken == '')) {
                lm = 'veloviewer'
            }
            svMap.setMapTypeId(lm);
        } else {
            if (typeof(mbCustomToken) !== 'undefined' && mbCustomToken != '') {
                svMap.setMapTypeId('custom');
            } else {
                svMap.setMapTypeId('veloviewer');
            }
        }

        var bounds = new google.maps.LatLngBounds();
        bounds.extend(new google.maps.LatLng(segment.minLat, segment.minLng));
        bounds.extend(new google.maps.LatLng(segment.maxLat, segment.maxLng));
        svMap.fitBounds(bounds);

        svPano = new google.maps.StreetViewPanorama(
            document.getElementById('svPano'), {
                enableCloseButton: true,
                //position: pos,
                /*pov: {
                    heading: bearing,
                    pitch: 0
                },*/
                visible: false
            });
        svMap.setStreetView(svPano);

        bgSVPoly = new google.maps.Polyline({
            path: la.map(function(d) {
                return new google.maps.LatLng(d.lat, d.lng);
            }),
            geodesic: true,
            strokeColor: '#FFF',
            strokeOpacity: 1.0,
            strokeWeight: 5,
            zIndex: 1
        });
        bgSVPoly.setMap(svMap);
        hlSVPoly = new google.maps.Polyline({
            path: la.map(function(d) {
                return new google.maps.LatLng(d.lat, d.lng);
            }),
            geodesic: true,
            strokeColor: '#000',
            strokeOpacity: 1.0,
            strokeWeight: 5,
            zIndex: 2
        });
        hlSVPoly.setMap(svMap);
        fgSVPoly = new google.maps.Polyline({
            path: la.map(function(d) {
                return new google.maps.LatLng(d.lat, d.lng);
            }),
            geodesic: true,
            strokeColor: '#FF032E',
            strokeOpacity: 1.0,
            strokeWeight: 2,
            zIndex: 3
        });
        fgSVPoly.setMap(svMap);

        setMapDetail('G', svMap);

        gmapMarkers.startPano = new google.maps.Marker({
            position: new google.maps.LatLng(la[0].lat, la[0].lng),
            map: svPano,
            icon: https + '://chart.googleapis.com/chart?chst=d_map_spin&chld=1.1|0|00FF00|13|b|Start'
        });
        gmapMarkers.startMap = new google.maps.Marker({
            position: new google.maps.LatLng(la[0].lat, la[0].lng),
            zIndex: 20,
            map: svMap,
            icon: {
                url: 'https://cf.veloviewer.com/img/live-start.svg',
                size: new google.maps.Size(60, 60),
                origin: new google.maps.Point(0, 0),
                anchor: new google.maps.Point(0, 0),
                scaledSize: new google.maps.Size(20, 20)
            }
        });

        gmapMarkers.endPano = new google.maps.Marker({
            position: new google.maps.LatLng(la[la.length - 1].lat, la[la.length - 1].lng),
            map: svPano,
            icon: https + '://chart.googleapis.com/chart?chst=d_map_spin&chld=1.1|0|FF032E|13|b|End'
        });
        gmapMarkers.endMap = new google.maps.Marker({
            position: new google.maps.LatLng(la[la.length - 1].lat, la[la.length - 1].lng),
            zIndex: 20,
            map: svMap,
            icon: {
                url: 'https://cf.veloviewer.com/img/live-end.svg',
                size: new google.maps.Size(60, 60),
                origin: new google.maps.Point(0, 0),
                anchor: new google.maps.Point(0, 0),
                scaledSize: new google.maps.Size(20, 20)
            }
        });

        svMarker = new google.maps.Marker({
            position: pos,
            zIndex: 30,
            map: svMap,
            icon: gMapCurPosIcon
        });

        svMap.setZoom(svMap.getZoom() == 0 ? 14 : svMap.getZoom());

        svMap.addListener('maptypeid_changed', setGMapAttribution);
        svMap.addListener('idle', setGMapAttribution);
        svMap.addListener('idle', setGMapDistMarkers);
        svMap.addListener('click', function (e) {
            if(debug) console.debug(JSON.stringify(e.latLng.toJSON(), null, 2));
        });

        svPano.addListener('position_changed', syncToPano);
        svPano.addListener('visible_changed', function() {
            if (typeof(setPanoMapWaymarkerSize) !== 'undefined') {
                setPanoMapWaymarkerSize();
            } else {
                if (svPano.getVisible()) {
                    d3.select('#svMap').style('width', '50%');
                    d3.select('#svPano').style('width', '50%');
                } else {
                    d3.select('#svMap').style('width', '100%');
                    d3.select('#svPano').style('width', '0%');
                }
                var c = svMap.getCenter();
                google.maps.event.trigger(svMap, "resize");
                google.maps.event.trigger(svPano, "resize");
                svMap.setCenter(c);
                setGMapAttribution();
            }
        });
        streetviewShown = true;

        if (typeof(route) !== 'undefined' || typeof(activity) !== 'undefined') {
            var control = document.createElement('div');
            control.index = 1;
            svMap.controls[google.maps.ControlPosition.RIGHT_TOP].push(control);
            d3.select(control).append('button').attr('id', 'svMapExplorerBtn')
                .attr('title', 'View Explorer Tiles ticked by this ' + (typeof(activity) !== 'undefined' ? 'activity' : 'route') + ', zoom right in to see all recorded points')
                .attr('style', 'width:25px;height:25px;margin-right:14px;background:#fff;padding:0px;border: 0px;border-radius: 2px 2px 0px 0px;display: block;border-bottom: solid 1px rgb(187, 187, 187)')
                .on('click', function() {
                    gMapShowExplorer = !d3.select(this).classed('active');
                    d3.select(this).classed('active', gMapShowExplorer);
                    d3.select(this).style('background', gMapShowExplorer ? 'rgb(187, 187, 187)' : '#fff');
                    gMapShowRecordedDatapoints();
                    gMapShowTickedExplorerTiles();
                })
                .html('<i class="icon-th""></i>');
            d3.select(control).append('button').attr('id', 'svMapZwiftBtn')
                .attr('title', 'Map settings')
                .attr('style', 'width:25px;height:25px;margin-right:14px;background:#fff;padding:0px;border: 0px;border-radius: 0px;display:block;border-bottom: solid 1px rgb(187, 187, 187)')
                .classed('active', lm_ZwiftMapsMarker)
                .style('background', lm_ZwiftMapsMarker ? 'rgb(187, 187, 187)' : '#fff')
                .on('click', function() {
                    lm_ZwiftMapsMarker = !lm_ZwiftMapsMarker;
                    setCookie('lm_ZwiftMapsMarker', lm_ZwiftMapsMarker ? '1' : '0', 365);
                    zwiftMapsG(lm_ZwiftMapsMarker);
                })
                .html('<div style="padding: 4px 0px 0px 5px;width:15px" id="showZwiftMaps">' + zwiftIconSVG + '</div>');
            d3.select(control).append('button').attr('id', 'svMapOptionsBtn')
                .attr('title', 'Map settings')
                .attr('style', 'width:25px;height:25px;margin-right:14px;background:#fff;padding:0px;border: 0px;border-radius: 0px 0px 2px 2px;display:block')
                .on('click', function() {
                    d3.select('#svMapConfigModal').style({
                        position: 'absolute',
                        left: (350 - d3.select('.lm_optionsContainter').node().getBoundingClientRect().x) + 'px',
                        width: '300px'
                    });
                    if (d3.select('#svMapConfigModal .modal-body').html() == '') {
                        d3.select('#svMapConfigModal').on('mouseover', function() {
                            //localMap.dragging.disable();
                            //localMap.scrollWheelZoom.disable();
                        })
                        d3.select('#svMapConfigModal').on('mouseout', function() {
                            //localMap.dragging.enable();
                            //localMap.scrollWheelZoom.enable();
                        })

                        var f = d3.select('#svMapConfigModal .modal-body').append('div').classed('form-horizontal', true);

                        var cg = f.append('div').classed('control-group', true).style('margin-bottom', '10px').attr('title', 'Snap StreetView man to track.');
                        cg.append('label').classed('control-label', true).text('Snap StreetView:');
                        cg.append('div').classed('controls', true).append('input')
                            .attr({
                                'id': 'svMapSnapSVCheckBox',
                                'class': 'svMapSnapSVCheckBox',
                                'type': 'checkbox',
                                'checked': typeof(getCookie('lm_snapStreetView')) === 'undefined' || +getCookie('lm_snapStreetView') == 1 ? 'checked' : null
                            })
                            .on('change', function() {
                                setCookie('lm_snapStreetView', this.checked ? 1 : 0, 365);
                            });

                        var cg = f.append('div').classed('control-group', true).style('margin-bottom', (cpref || cpref == 'r' == 'a' ? '' : '1') + '0px').attr('title', 'Show distance markers.');
                        cg.append('label').classed('control-label', true).text('Distance markers:');
                        cg.append('div').classed('controls', true).append('input')
                            .attr({
                                'id': 'svMapDistanceMarkerCheckBox',
                                'class': 'svMapDistanceMarkerCheckBox',
                                'type': 'checkbox',
                                'checked': typeof(getCookie('lm_distanceMarker')) === 'undefined' || +getCookie('lm_distanceMarker') == 1 ? 'checked' : null
                            })
                            .on('change', function() {
                                setCookie('lm_distanceMarker', this.checked ? 1 : 0, 365);
                                setGMapDistMarkers();
                            });

                        var cg = f.append('div').classed('control-group', true).style('margin-bottom', (cpref || cpref == 'r' == 'a' ? '' : '1') + '0px').attr('title', 'Reverse distance markers.');
                        cg.append('label').classed('control-label', true).text('Reverse distance markers:');
                        cg.append('div').classed('controls', true).append('input')
                            .attr({
                                'id': 'svMapRDistanceMarkerCheckBox',
                                'class': 'svMapRDistanceMarkerCheckBox',
                                'type': 'checkbox',
                                'checked': +getCookie('lm_rDistanceMarker') == 1 ? 'checked' : null
                            })
                            .on('change', function() {
                                setCookie('lm_rDistanceMarker', this.checked ? 1 : 0, 365);
                                setGMapDistMarkers();
                            });
                    }
                    $('#svMapConfigModal').modal({
                        backdrop: false
                    });
                })
                .html('<i class="icon-cog""></i>');

            var dialogObj = d3.select(control).append('div').attr('class', 'lm_optionsContainter');

            addModalPopup('svMapConfig', 'Map Settings', undefined, 0, dialogObj);

            google.maps.event.addListener(svMap, 'bounds_changed', gMapShowRecordedDatapoints);
        }
        window.setTimeout(setGMapAttribution, 2000);
        window.setTimeout(setGMapAttribution, 4000);
        window.setTimeout(setGMapAttribution, 10000);

        if (typeof(gmapLogo) !== 'undefined') {
            gmapLogo();
        }
        zwiftMapsG(lm_ZwiftMapsMarker);
    }
}

var gMapShowExplorer = true;

function gMapShowRecordedDatapoints() {
    (typeof(activity) !== 'undefined' ? activity : route).latLngArr2Copy.forEach(function(d) {
        if (gMapShowExplorer && svMap.getZoom() >= 18 && d.lat <= svMap.getBounds().getNorthEast().lat() && d.lat >= svMap.getBounds().getSouthWest().lat() && d.lng <= svMap.getBounds().getNorthEast().lng() && d.lng >= svMap.getBounds().getSouthWest().lng()) {
            if (!d.marker) {
                d.marker = new google.maps.Marker({
                    position: {
                        lat: d.lat,
                        lng: d.lng
                    },
                    zIndex: 10,
                    icon: {
                        path: google.maps.SymbolPath.CIRCLE,
                        fillOpacity: 0.8,
                        fillColor: '#000',
                        strokeOpacity: 0,
                        scale: 1.5 //pixels
                    }
                });
            }
            if (d.marker.getMap() == null) d.marker.setMap(svMap);
        } else {
            if (d.marker) d.marker.setMap(null);
        }
    })
}

function gMapShowTickedExplorerTiles() {
    var obj = typeof(activity) !== 'undefined' ? activity : route;
    if (!obj.tiles) {
        getActMapTiles(obj, explorerZoom, 0, false);
    }
    obj.tiles.forEach(function(d) {
        if (gMapShowExplorer) {
            if (!d.rect) {
                d.rect = new google.maps.Rectangle({
                    strokeColor: explorerTileStyle.color,
                    strokeOpacity: explorerTileStyle.opacity,
                    strokeWeight: explorerTileStyle.weight,
                    fillColor: explorerTileStyle.fillColor,
                    fillOpacity: explorerTileStyle.fillOpacity,
                    map: svMap,
                    bounds: {
                        north: d.tl.y,
                        south: d.br.y,
                        east: d.br.x,
                        west: d.tl.x
                    }
                });
            }
            if (d.rect.getMap() == null) d.rect.setMap(svMap);
        } else {
            if (d.rect) d.rect.setMap(null);
        }
    })
}

var reverseStyleSheet = null;

function setGMapDistMarker(text, position, map) {
    var reverse = typeof(getCookie('lm_rDistanceMarker')) !== 'undefined' && +getCookie('lm_rDistanceMarker') == 1;
    var highlight = reverse && ['1', '2', '3', '5', '10'].indexOf(text) > -1;
    if (reverse && reverseStyleSheet == null) {
        reverseStyleSheet = document.createElement('style')
        reverseStyleSheet.innerHTML = ".infoBox:before{border-right: 6px solid #000;} .ibHighlight:before{border-right: 7px solid #000; border-top: 7px solid transparent; border-bottom: 7px solid transparent;}";
        document.body.appendChild(reverseStyleSheet);
    }
    if (!reverse && reverseStyleSheet != null) {
        document.body.removeChild(reverseStyleSheet);
        reverseStyleSheet = null;
    }
    var myOptions = {
        content: text,
        boxStyle: {
            border: "0px",
            textAlign: "center",
            fontSize: highlight ? "10px" : "8px",
            //height: "8px",
            padding: "2px 2px 1px 0px",
            color: reverse ? '#fff' : '#000',
            'background-color': reverse ? '#000' : '#fff',
            //'font-weight': 'bold'
        },
        disableAutoPan: true,
        pixelOffset: highlight ? new google.maps.Size(8, -7) : new google.maps.Size(8, -6),
        position: position, //new google.maps.LatLng(49.47216, -123.76307)
        closeBoxURL: "",
        isHidden: false,
        zIndex: 11,
        pane: "overlayShadow",
        enableEventPropagation: true,
        boxClass: highlight ? 'infoBox ibHighlight' : 'infoBox'
    };

    var ibLabel = new InfoBox(myOptions);
    ibLabel.open(map);

    var marker = new google.maps.Marker({
        position: position,
        zIndex: 10,
        icon: {
            path: google.maps.SymbolPath.CIRCLE,
            fillOpacity: 0.8,
            fillColor: '#000',
            strokeOpacity: 0,
            scale: 2 //pixels
        }
    });
    marker.setMap(map);

    return [ibLabel, marker];
}

function setGMapDistMarkers() {
    if (svMap.getBounds() != null) {
        gMapMarkerArr2.forEach(function(d) {
            d[0].setMap(null);
            d[1].setMap(null);
        });
        gMapMarkerArr2 = [];
        if (getParameterByName('p') != '' || (typeof(getCookie('lm_distanceMarker')) !== 'undefined' && +getCookie('lm_distanceMarker') == 0)) return;
        var reverse = typeof(getCookie('lm_rDistanceMarker')) !== 'undefined' && +getCookie('lm_rDistanceMarker') == 1;
        var dist = 1;
        if (svMap.zoom >= 17) dist = 0.1;
        if (svMap.zoom == 16) dist = 0.25;
        if (svMap.zoom == 15) dist = 0.5;
        if (svMap.zoom == 14) dist = 1;
        if (svMap.zoom == 13) dist = 2;
        if (svMap.zoom == 12) dist = 5;
        if (svMap.zoom == 11) dist = 10;
        if (svMap.zoom <= 10) dist = 25;

        var svMapB = svMap.getBounds();
        var svMapNE = svMapB.getNorthEast();
        var svMapSW = svMapB.getSouthWest();

        gMapMarkerArr = d3.range(0, segment.distance + 1, dist / lrgLenMult).map(function(d, i) {
            return {
                d: d,
                t: i * dist,
                i: reverse ? d3.bisectRight(segment.distanceArr2Copy, route.distance - d) : d3.bisectLeft(segment.distanceArr2Copy, d)
            }
        }).filter(function(d) {
            return d.i < segment.distanceArr2Copy.length && d.d != 0;
        }).map(function(d) {
            var ll = segment.latLngArr2Copy[d.i]
            if (reverse) {
                if (route.distance - segment.distanceArr2Copy[d.i] != d.d) {
                    var dd = segment.distanceArr2Copy[d.i] - segment.distanceArr2Copy[d.i - 1];
                    var de = d.d - (route.distance - segment.distanceArr2Copy[d.i - 1]);
                    ll = {
                        lat: segment.latLngArr2Copy[d.i - 1].lat - (de / dd) * (segment.latLngArr2Copy[d.i].lat - segment.latLngArr2Copy[d.i - 1].lat),
                        lng: segment.latLngArr2Copy[d.i - 1].lng - (de / dd) * (segment.latLngArr2Copy[d.i].lng - segment.latLngArr2Copy[d.i - 1].lng)
                    };
                }
            } else {
                if (segment.distanceArr2Copy[d.i] != d.d) {
                    var dd = segment.distanceArr2Copy[d.i] - segment.distanceArr2Copy[d.i - 1];
                    var de = d.d - segment.distanceArr2Copy[d.i - 1];
                    ll = {
                        lat: segment.latLngArr2Copy[d.i - 1].lat + (de / dd) * (segment.latLngArr2Copy[d.i].lat - segment.latLngArr2Copy[d.i - 1].lat),
                        lng: segment.latLngArr2Copy[d.i - 1].lng + (de / dd) * (segment.latLngArr2Copy[d.i].lng - segment.latLngArr2Copy[d.i - 1].lng)
                    };
                }
            }
            return {
                i: d.i,
                t: (Math.round(100 * d.t) / 100).toString(),
                ll: ll
            };
        }).filter(function(d) {
            return d.i >= filtIndExtent[0] && d.i <= filtIndExtent[1] &&
                d.ll.lat >= svMapSW.lat() && d.ll.lat <= svMapNE.lat() && d.ll.lng >= svMapSW.lng() && d.ll.lng <= svMapNE.lng()
        });

        gMapMarkerArr.forEach(function(d) {
            gMapMarkerArr2.push(setGMapDistMarker(d.t, new google.maps.LatLng(d.ll.lat, d.ll.lng), svMap));
        });
        if (typeof(p3dpPolylineClick) !== 'undefined') p3dpPolylineClick();
    }
}

function setGMapAttribution() {
    window.setTimeout(function() {
        switch (svMap.mapTypeId) {
            case 'custom':
                d3.select('.gm-style-cc span').each(function() {
                    d3.select(this).html('Maps © <a style="color: rgb(68, 68, 68)" href="http://www.mapbox.com">MapBox</a>, Data © <a style="color: rgb(68, 68, 68)" href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>').style('display', null);
                    d3.select(this.parentElement.parentElement.parentElement).style('width', null);
                });
                break;
            case 'veloviewer':
            case 'landscape':
            case 'outdoors':
            case 'ocm':
                d3.select('.gm-style-cc span').each(function() {
                    d3.select(this).html('Maps © <a style="color: rgb(68, 68, 68)" href="http://www.thunderforest.com">Thunderforest</a>, Data © <a style="color: rgb(68, 68, 68)" href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>').style('display', null);
                    d3.select(this.parentElement.parentElement.parentElement).style('width', null);
                });
                break;
            case 'osm':
                d3.select('.gm-style-cc span').each(function() {
                    d3.select(this).html('© <a style="color: rgb(68, 68, 68)" href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>').style('display', null);
                    d3.select(this.parentElement.parentElement.parentElement).style('width', null);
                });
                break;
            case 'baw':
                d3.select('.gm-style-cc span').each(function() {
                    d3.select(this).html('Map tiles by <a style="color: rgb(68, 68, 68)" href="http://stamen.com">Stamen Design</a>, under <a style="color: rgb(68, 68, 68)" href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a style="color: rgb(68, 68, 68)" href="http://openstreetmap.org">OpenStreetMap</a>, under <a style="color: rgb(68, 68, 68)" href="http://www.openstreetmap.org/copyright">ODbL</a>.').style('display', null);
                    d3.select(this.parentElement.parentElement.parentElement).style('width', null);
                });
                break;
            case 'osuk':
                d3.select('.gm-style-cc span').each(function() {
                    d3.select(this).html('<a style="color: rgb(68, 68, 68)" href="http://www.ordnancesurvey.co.uk/oswebsite/opendata/">Ordnance Survey OpenData</a> © Crown copyright and database right 2010 <a style="color: rgb(68, 68, 68)" href="http://www.klokantech.com/" target="_blank">Klokan Technologies GmbH</a>').style('display', null);
                    d3.select(this.parentElement.parentElement.parentElement).style('width', null);
                });
                break;
        }
        setCookie('lmap', svMap.mapTypeId, 365);

        /*window.setTimeout(function() {
            if (d3.select('.gm-fullscreen-control')[0][0] != null) {
                d3.select(d3.select('.gm-fullscreen-control').node().parentElement).style('display', null).style('pointer-events', 'none');
                d3.select('.gm-fullscreen-control').style('pointer-events', 'auto').on('click',
                    function() {
                        window.setTimeout(function() {
                            google.maps.event.trigger(svMap, "resize")
                        }, 500);
                    });
            }
        }, 200);*/
    }, 100);
}

function setSvExtent() {
    var la = segment.latLngArr2Copy; //(typeof(llObj) !== 'undefined' ? llObj.data2 : segment.latLngArr2Copy);
    var da = segment.distanceArr2Copy; //(typeof(distObj) !== 'undefined' ? distObj.data : segment.distanceArr2Copy);
    if (typeof(filtIndExtent) === 'undefined' || typeof(filtIndExtent[0]) === 'undefined') {
        filtIndExtent = [0, la.length];
    }
    var llArr = la.slice(Math.max(0, filtIndExtent[0]), filtIndExtent[1] + 1);
    hlSVPoly.setPath(llArr.map(function(d) {
        return new google.maps.LatLng(d.lat, d.lng);
    }));
    var bounds = new google.maps.LatLngBounds();
    var latExt = d3.extent(llArr, function(d) {
        return d.lat
    }).sort(d3.ascending);
    var lngExt = d3.extent(llArr, function(d) {
        return d.lng
    }).sort(d3.ascending);
    bounds.extend(new google.maps.LatLng(latExt[0], lngExt[0]));
    bounds.extend(new google.maps.LatLng(latExt[1], lngExt[1]));
    svMap.fitBounds(bounds);

    if (llArr.length != la.length) {
        setSVPano(llArr[0], llArr[1], false);
    }

    if (typeof(xmlDataObj) !== 'undefined' && xmlDataObj.routes && xmlDataObj.routes.length > 0 && typeof(xmlDataObj.routes[0].startDist) !== 'undefined') {
        xmlDataObj.routes.forEach(function(d, i) {
            d.poly.setMap(null);
            if (d.shown) {
                var lle;

                if (filtIndExtent[1] == route.distanceArr2Copy.length - 1) {
                    if (filtIndExtent[0] == 0) {
                        lle = d.lle;
                    } else {
                        var dl = da[filtIndExtent[1]] - da[filtIndExtent[0]];
                        lle = d.lle.filter(function(e) { return d.startDist + e.dist /*- raceStages[0].kmZero*/ >= xmlDataObj.totalDist - dl });
                    }
                } else {
                    lle = d.lle.filter(function(e) { return d.startDist + e.dist - (typeof(raceStages) === 'undefined' ? 0 : raceStages[0].kmZero) >= da[filtIndExtent[0]] && d.startDist + e.dist - (typeof(raceStages) === 'undefined' ? 0 : raceStages[0].kmZero) <= da[filtIndExtent[1]] });
                }

                if (lle.length > 0) {
                    d.poly = new google.maps.Polyline({
                        path: lle.map(function(e, j) {
                            return new google.maps.LatLng(e.lat, e.lng)
                        }),
                        geodesic: true,
                        strokeColor: d.colour,
                        strokeOpacity: 1.0,
                        strokeWeight: 2,
                        zIndex: 100000,
                        map: svMap
                    });
                }
            }
        });
        /*compareGPXObj.poly.setMap(null);
        var path = [];
        if (filtIndExtent[1] == route.distanceArr2.length - 1) {
            if (filtIndExtent[0] == 0) {
                path = compareGPXObj.lled;
            } else {
                var diff = route.distance - compareGPXObj.lled.last().d;
                path = compareGPXObj.lled.slice(d3.bisect(compareGPXObj.lled.map(function(d) { return d.d }), route.distanceArr2[filtIndExtent[0]] + (+raceStages[0].kmZero) - diff));
            }
        } else {
            path = compareGPXObj.lled.slice(d3.bisect(compareGPXObj.lled.map(function(d) { return d.d }), route.distanceArr2[filtIndExtent[0]] + (+raceStages[0].kmZero)), d3.bisect(compareGPXObj.lled.map(function(d) { return d.d }), route.distanceArr2[filtIndExtent[1]] + (+raceStages[0].kmZero)));
        }
        compareGPXObj.poly = new google.maps.Polyline({
            path: path,
            geodesic: true,
            strokeColor: '#ff00ff',
            strokeOpacity: 1.0,
            strokeWeight: 2,
            zIndex: 100000
        });
        compareGPXObj.poly.setMap(svMap);*/
    }
    google.maps.event.trigger(svMap, "resize");
}

function setSVPano(ll0, ll1, setCenter) {
    if (svPano.getVisible()) {
        if (setSVPanoTimer != null) {
            window.clearTimeout(setSVPanoTimer);
            setSVPanoTimer = null;
        }
        setSVPanoTimer = setTimeout(function() {
            svPano.setVisible(true);
            var pos = new google.maps.LatLng(ll0.lat, ll0.lng);
            svPano.setPosition(pos);
            var bearing = getBearing(ll0.lat, ll0.lng, ll1.lat, ll1.lng);
            svPano.setPov({
                heading: bearing,
                pitch: 0
            })
            if (setCenter) {
                svMap.setCenter({
                    lat: ll0.lat,
                    lng: ll0.lng
                });
            }
            setSVPanoTimer = null;
        }, 1000);
    }
}

var isSnapping = false,
    snappingTimeout = null;

function syncToPano() {
    //var positionCell = document.getElementById('position-cell');
    //positionCell.firstChild.nodeValue = panorama.getPosition() + '';
    //setMapMarker(elevChart.xScale().invert(d3.event.x - this.getBoundingClientRect().left), d3.event.x - this.getBoundingClientRect().left);
    if (typeof(d3.select('#svPano').on('click')) === 'undefined') {
        d3.select('#svPano').on('click', function() {
            if (snappingTimeout != null) {
                window.clearTimeout(snappingTimeout);
            }
            isSnapping = true;
            console.info('clicked');
        });
    }


    if (!isPanningSV) {
        var la = segment.latLngArr2Copy;
        var da = segment.distanceArr2Copy;
        var lat = svPano.getPosition().lat();
        var lng = svPano.getPosition().lng();
        var rp = [];
        var closest = null;
        for (var i = 0; i < la.length; i++) {
            var e = la[i];
            var d = distLatLon(e.lat, e.lng, lat, lng);
            if (d < 75) {
                rp.push({
                    i: i,
                    d: d
                });
            }
            if (closest == null || closest.d > d) {
                closest = {
                    i: i == la.length - 1 ? i - 1 : i,
                    d: d
                };
            }
        }

        if (!isSnapping && (typeof(getCookie('lm_snapStreetView')) === 'undefined' || +getCookie('lm_snapStreetView') == 1)) {
            isSnapping = true;
            setSVPano(la[closest.i], la[closest.i + 1], false);
            return;
        }
        if (snappingTimeout != null) {
            window.clearTimeout(snappingTimeout);
        }
        snappingTimeout = window.setTimeout(function() {
            isSnapping = false;
            snappingTimeout = null;
        }, 3000);

        if (rp.length > 0) {
            rp.sort(function(a, b) {
                return a.d - b.d
            });
            var ll0 = la[rp[0].i - (rp[0].i == la.length - 1 ? 1 : 0)];
            var ll1 = la[rp[0].i + (rp[0].i == la.length - 1 ? 0 : 1)];
            svPano.setPov({
                heading: getBearing(ll0.lat, ll0.lng, ll1.lat, ll1.lng),
                pitch: 0
            })
            if (typeof(elevChart) !== 'undefined') {
                if (typeof(elevChart.xScale) !== 'undefined') {
                    setMapMarker(da[rp[0].i], elevChart.xScale()(da[rp[0].i]));
                } else {
                    setMapMarker(da[rp[0].i]);
                }
            }
        }
    }
    isPanningSV = false;
}


/* 3D Map */

var xxExt, yyExt, mtxExt, mtyExt, tilePadding = {
        N: 2,
        S: 2,
        E: 2,
        W: 2
    },
    map3dzoom = 1,
    map3dpo, draw3dmapTimer = null;
if (typeof(doubleLogoSize) !== 'undefined') {
    tilePadding = {
        N: 4,
        S: 4,
        E: 4,
        W: 4
    };
}
if (getParameterByName('pad') != '') {
    var padA = getParameterByName('pad').split(',');
    switch (padA.length) {
        case 1:
            tilePadding = {
                N: +padA[0],
                S: +padA[0],
                E: +padA[0],
                W: +padA[0]
            };
            break;
        case 2:
            tilePadding = {
                N: +padA[0],
                S: +padA[0],
                E: +padA[1],
                W: +padA[1]
            };
            break;
        case 4:
            tilePadding = {
                N: +padA[0],
                S: +padA[2],
                E: +padA[1],
                W: +padA[3]
            };
            break;
    }
}

var map3ddrawn = false;

function setup3dmap() {
    d3.selectAll('#myTabs').append('li').classed('hidden-phone', true).append('a').attr({
        'href': '#map3d',
        'data-toggle': 'tab'
    }).html('3D Map');
    var map3dTab = d3.selectAll('.tab-content')
        .append('div')
        .style({
            'height': '550px'
        })
        .attr({
            'class': 'tab-pane',
            'id': 'map3d'
        })

    map3dTab.style('position', 'relative')
        .append('div')
        .attr('id', 'map3dScale')
        .style('position', 'absolute')
        .append('div')
        .attr('id', 'map3dWrapper')
        .style({
            '-webkit-perspective': '5000px',
            '-moz-perspective': '5000px',
            'perspective': '5000px',
            'position': 'absolute',
            'top': '0px',
            'left': '0px'
        })
        .append('div')
        .attr('id', 'map3dContent')
        .style({
            '-webkit-transform': 'rotateX(' + spinYVal2 + 'deg)',
            '-moz-transform': 'rotateX(' + spinYVal2 + 'deg)',
            'transform': 'rotateX(' + spinYVal2 + 'deg)',
            '-webkit-transform-style': 'preserve-3d',
            '-moz-transform-style': 'preserve-3d',
            'transform-style': 'preserve-3d',
            'position': 'relative',
            'pointer-events': 'none'
        });
    d3.select('#map3d')
        .style('background', 'white')
        .style('margin', '-10px -10px 0px')
        .style('overflow', 'hidden');

    $('a[data-toggle="tab"][href="#map3d"]').on('shown', function(e) {
        curTab = 'map3d';
        d3.selectAll('.floatingVVLogo').style('display', null);
        d3.select('#typeFlipperDiv').style('display', 'none');
        if (typeof(brushExtent) !== 'undefined') {
            if (brushExtent[0] == brushExtent[1]) {
                filtIndExtent = [0, segment.latLngArr2Copy.length - 1];
            } else {
                filtIndExtent = [d3.bisect(segment.distanceArr2Copy, brushExtent[0]) - 1, Math.min(segment.distanceArr2Copy.length - 1, d3.bisectLeft(segment.distanceArr2Copy, brushExtent[1]))];
            }
            segment.latLngArr2 = segment.latLngArr2Copy.slice(Math.max(0, filtIndExtent[0]), filtIndExtent[1] + 1);
            segment.elevationArr2 = segment.elevationArr2Copy.slice(Math.max(0, filtIndExtent[0]), filtIndExtent[1] + 1);
            segment.distanceArr2 = segment.distanceArr2Copy.slice(Math.max(0, filtIndExtent[0]), filtIndExtent[1] + 1);
        }
        draw3dmap(!map3ddrawn);
    });
}

function draw3dmap(isFirst) {
    if (isFirst) {
        draw3dmap2(true);
    } else {
        window.clearTimeout(draw3dmapTimer);
        draw3dmapTimer = window.setTimeout(function() {
            window.clearTimeout(draw3dmapTimer);
            draw3dmapTimer = null;
            draw3dmap2(false)
        }, 500);

    }
}

function draw3dmap2(isFirst) {
    if (segment.latLngArr2.length <= 1) {
        return;
    }
    if (getCookie('lmap') == 'osuk' && typeof(svMap) === 'undefined') {
        loadstreetview();
        draw3dmap2(isFirst);
        return;
    }
    if (getCookie('lmap') == 'osuk' && typeof(svMap.getProjection()) === 'undefined') {
        window.setTimeout(function() {
            draw3dmap2(isFirst);
        }, 100);
        return;
    }

    if (isFirst) {
        /*d3.select('body').append('div').attr('class', 'floatingVVLogo')
            .attr('style', 'position:fixed;bottom:10px;left:40px')
            .html('<img src="' + https + '://cf.veloviewer.com/img/logo30blackred.png"><span style="vertical-align: bottom;margin: 0px 0px 5px 10px;">powered by</span><div class="poweredbystrava" style="vertical-align: bottom;"></div>');
*/
        var sizeMult = 1; //Math.min(1, parseInt(d3.select('body').style('width')) / 600);

        var logoCont = d3.select('body').append('div').attr('class', 'floatingVVLogo')
            .attr('style', 'position:fixed;bottom:10px;left:40px').append('svg')
            .style({
                height: '30px',
                width: '250px'
            })
            .append('g');

        // powered by STRAVA
        logoCont.append('g')
            .attr("transform", function() {
                return "translate(175,12) scale(0.6, 0.6)";
            })
            .append('text')
            .style('font-size', '1.5em')
            .style('fill', p3dFG)
            .text('powered by');

        // STRAVA logo
        var stravaLogoColour = '#FC4C02';
        var ppslg = logoCont.append('g')
            .attr("transform", function() {
                return "translate(175,15) scale(0.3, 0.3)";
            });
        ppslg.append('path')
            .attr('fill', stravaLogoColour)
            .attr('d', "M19.161621,40.397949c-3.805664,0-7.35791-0.529785-10.649902-1.575684 C5.219238,37.769043,2.383301,36.194824,0,34.101074l6.67041-7.949707c2.027344,1.563477,4.166016,2.685059,6.403809,3.359375 c2.241699,0.676758,4.467773,1.015137,6.673828,1.015137c1.141113,0,1.956055-0.143555,2.456055-0.424805 c0.501953-0.286621,0.746094-0.678711,0.746094-1.174316v-0.106445c0-0.538086-0.368652-0.98877-1.094238-1.337402 c-0.725586-0.356445-2.092773-0.728027-4.084961-1.118164c-2.098145-0.429688-4.101562-0.930664-6.002441-1.498535 c-1.904785-0.564453-3.575684-1.297363-5.016113-2.187988c-1.442871-0.886719-2.589355-2.011719-3.445312-3.362305 c-0.854004-1.354004-1.28125-3.009766-1.28125-4.964844v-0.106934c0-1.780762,0.346191-3.437012,1.042969-4.965332 C3.756836,7.749512,4.772949,6.412109,6.10791,5.276855c1.335449-1.139648,2.993164-2.027344,4.969727-2.671875 c1.967773-0.639648,4.238281-0.959473,6.804199-0.959473c3.625,0,6.800781,0.428711,9.523926,1.284668 c2.723145,0.848145,5.166992,2.130859,7.34082,3.837891l-6.083496,8.435059c-1.779785-1.28418-3.658203-2.217285-5.631836-2.806152 c-1.97998-0.588379-3.831543-0.882812-5.57959-0.882812c-0.922852,0-1.607422,0.142578-2.051758,0.427734 c-0.452637,0.284668-0.667969,0.660156-0.667969,1.121094v0.105469c0,0.501953,0.334473,0.929199,1.013184,1.286133 c0.679199,0.354004,1.994141,0.729004,3.948242,1.120117c2.385254,0.424805,4.554199,0.941895,6.516602,1.543457 c1.953125,0.61084,3.639648,1.381348,5.041504,2.32666c1.405273,0.942383,2.494141,2.067383,3.256836,3.388184 c0.763672,1.316895,1.147461,2.92041,1.147461,4.802734v0.109863c0,1.954102-0.390137,3.719727-1.17627,5.282715 c-0.780762,1.567383-1.88623,2.890137-3.309082,3.978516c-1.424316,1.08252-3.151855,1.917969-5.179199,2.506348 C23.966309,40.103027,21.68457,40.397949,19.161621,40.397949L19.161621,40.397949z");

        ppslg.append('polygon')
            .attr('fill', stravaLogoColour)
            .attr('points', "45.95459,12.902832 34.958984,12.902832 34.958984,2.342285 69.446777,2.342285 69.446777,12.902832 58.447754,12.902832 58.447754,39.69873 45.95459,39.69873 45.95459,12.902832");

        ppslg.append('path')
            .attr('fill', stravaLogoColour)
            .attr('d', "M89.086914,20.115234c1.495605,0,2.671875-0.321289,3.521484-0.960449 c0.854004-0.641602,1.283203-1.534668,1.283203-2.672852v-0.10791c0-1.207031-0.429199-2.108398-1.283203-2.689941 c-0.849609-0.588379-2.011719-0.879883-3.466309-0.879883h-5.447754v7.311035H89.086914L89.086914,20.115234z M71.203125,2.342285 h18.258301c3.344238,0,6.092773,0.383789,8.244141,1.148438c2.15625,0.763672,3.886719,1.806641,5.20459,3.123535 c1.141602,1.135254,1.994629,2.418945,2.566406,3.837402c0.566406,1.423828,0.853516,3.102051,0.853516,5.01416v0.11377 c0,2.737305-0.658691,5.050781-1.979492,6.93457c-1.312988,1.885254-3.109375,3.384766-5.390625,4.48291l8.698242,12.70166 H93.40918l-7.047363-10.67334h-0.101562h-2.565918v10.67334H71.203125V2.342285L71.203125,2.342285z");

        ppslg.append('polygon')
            .attr('fill', stravaLogoColour)
            .attr('points', "179.889648,23.627441 188.032227,39.69873 200,39.69873 179.889648,0 159.781738,39.69873 171.753418,39.69873 179.889648,23.627441");

        ppslg.append('polygon')
            .attr('fill', stravaLogoColour)
            .attr('points', "123.918457,23.627441 132.058105,39.69873 144.028809,39.69873 123.918457,0 103.818848,39.69873 115.78418,39.69873 123.918457,23.627441");

        ppslg.append('polygon')
            .attr('fill', stravaLogoColour)
            .attr('points', "151.912598,18.412598 143.76709,2.342285 131.796387,2.342285 151.912598,42.041016 172.01416,2.342285 160.051758,2.342285 151.912598,18.412598");

        //veloviewer logo
        var vvg = logoCont.append('g')
            .attr("transform", function() {
                return "translate(2,0)";
            })
            .append('g')
            .attr('transform', 'matrix(1.25,0,0,-1.25,0,29.999997)')
            .append('g')
            .attr('transform', 'matrix(1.760792,0,0,1.760792,-12.151382,-8.963022)');
        vvg.append('path')
            .attr('transform', 'translate(30.6738,8.6094)')
            .attr('d', 'm 0,0 c -1.061,0 -1.82,0.887 -1.82,1.933 l 0,0.03 c 0,1.045 0.696,1.916 1.788,1.916 1.061,0 1.837,-0.887 1.837,-1.946 l 0,-0.033 C 1.805,0.871 1.092,0 0,0 m -0.032,-2.549 c 2.125,0 3.798,1.218 4.451,2.891 L 4.421,0.35 3.555,1.871 C 3.131,2.629 2.985,2.885 2.657,3.469 2.001,4.633 1.047,6.309 1.047,6.309 0.714,6.38 0.363,6.412 0,6.412 c -2.739,0 -4.733,-2.043 -4.733,-4.479 l 0,-0.033 c 0,-2.437 1.979,-4.449 4.701,-4.449 m -7.471,0.207 2.992,0 0,12.158 -2.992,0 0,-12.158 z m -5.588,4.987 c 0.158,0.949 0.696,1.55 1.487,1.55 0.824,0 1.394,-0.601 1.504,-1.55 l -2.991,0 z m 1.757,-5.194 c 1.694,0 2.881,0.697 3.704,1.742 L -9.292,0.57 c -0.618,-0.601 -1.171,-0.871 -1.9,-0.871 -0.933,0 -1.615,0.477 -1.852,1.41 l 5.731,0 c 0.016,0.205 0.016,0.428 0.016,0.618 0,2.517 -1.362,4.685 -4.307,4.685 -2.532,0 -4.321,-1.978 -4.321,-4.479 l 0,-0.033 c 0,-2.643 1.9,-4.449 4.591,-4.449')
            .attr('style', 'fill:' + p3dFG + ';stroke:none');
        vvg.append('path')
            .attr('transform', 'translate(6.9233,14.8223)')
            .attr('d', 'M 0,0 4.879,-8.619 9.742,0 6.852,0 4.879,-3.465 2.907,0 0,0 z')
            .attr('style', 'fill:' + p3dFG + ';stroke:none');
        vvg.append('path')
            .attr('transform', 'translate(32.9336,14.8223)')
            .attr('d', 'M 0,0 4.879,-8.619 9.742,0 6.852,0 4.879,-3.465 2.907,0 0,0 z')
            .attr('style', 'fill:' + vvCol + ';stroke:none');
        vvg.append('path')
            .attr('transform', 'translate(72.4004,6.2676)')
            .attr('d', 'm 0,0 3.008,0 0,2.676 c 0,1.963 0.887,2.865 2.453,2.865 l 0.254,0 0,3.167 C 4.291,8.77 3.498,8.01 3.008,6.838 l 0,1.726 L 0,8.564 0,0 z m -5.508,4.986 c 0.158,0.95 0.696,1.551 1.488,1.551 0.823,0 1.393,-0.601 1.504,-1.551 l -2.992,0 z m 1.756,-5.193 c 1.695,0 2.883,0.697 3.705,1.742 l -1.662,1.377 c -0.617,-0.601 -1.172,-0.871 -1.9,-0.871 -0.934,0 -1.614,0.477 -1.852,1.41 l 5.731,0 c 0.015,0.205 0.015,0.428 0.015,0.617 0,2.518 -1.361,4.686 -4.305,4.686 -2.533,0 -4.322,-1.979 -4.322,-4.48 l 0,-0.032 c 0,-2.643 1.899,-4.449 4.59,-4.449 m -13.896,0.143 2.564,0 1.426,4.464 1.392,-4.464 2.596,0 2.645,8.628 -2.897,0 -1.156,-4.337 -1.33,4.369 -2.469,0 -1.33,-4.337 -1.125,4.305 -2.928,0 2.612,-8.628 z m -7.122,5.05 c 0.159,0.95 0.698,1.551 1.489,1.551 0.824,0 1.392,-0.601 1.504,-1.551 l -2.993,0 z m 1.758,-5.193 c 1.694,0 2.881,0.697 3.705,1.742 l -1.662,1.377 c -0.619,-0.601 -1.172,-0.871 -1.9,-0.871 -0.934,0 -1.615,0.477 -1.852,1.41 l 5.731,0 c 0.015,0.205 0.015,0.428 0.015,0.617 0,2.518 -1.361,4.686 -4.306,4.686 -2.533,0 -4.323,-1.979 -4.323,-4.48 l 0,-0.032 c 0,-2.643 1.901,-4.449 4.592,-4.449 M -30.373,0 l 2.992,0 0,8.564 -2.992,0 0,-8.564 z')
            .attr('style', 'fill:' + vvCol + ';stroke:none');
        vvg.append('path')
            .attr('transform', 'translate(43.5332,15.4336)')
            .attr('d', 'M 0,0 C 0.826,0 1.496,0.67 1.496,1.496 1.496,2.322 0.826,2.992 0,2.992 -0.827,2.992 -1.496,2.322 -1.496,1.496 -1.496,0.67 -0.827,0 0,0')
            .attr('style', 'fill:' + vvCol + ';stroke:none');
    }

    var isZwift = false;
    var zwiftObj;
    if (segment.latLngArr2[0].lat < z_watopia.v_north &&
        segment.latLngArr2[0].lat > z_watopia.v_south &&
        segment.latLngArr2[0].lng < z_watopia.v_east &&
        segment.latLngArr2[0].lng > z_watopia.v_west) {

        isZwift = true;
        zwiftObj = z_watopia;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_london.v_north &&
        segment.latLngArr2[0].lat > z_london.v_south &&
        segment.latLngArr2[0].lng < z_london.v_east &&
        segment.latLngArr2[0].lng > z_london.v_west) {

        isZwift = true;
        zwiftObj = z_london;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_newyork.v_north &&
        segment.latLngArr2[0].lat > z_newyork.v_south &&
        segment.latLngArr2[0].lng < z_newyork.v_east &&
        segment.latLngArr2[0].lng > z_newyork.v_west) {

        isZwift = true;
        zwiftObj = z_newyork;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_richmond.v_north &&
        segment.latLngArr2[0].lat > z_richmond.v_south &&
        segment.latLngArr2[0].lng < z_richmond.v_east &&
        segment.latLngArr2[0].lng > z_richmond.v_west) {

        isZwift = true;
        zwiftObj = z_richmond;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_innsbruck.v_north &&
        segment.latLngArr2[0].lat > z_innsbruck.v_south &&
        segment.latLngArr2[0].lng < z_innsbruck.v_east &&
        segment.latLngArr2[0].lng > z_innsbruck.v_west) {

        isZwift = true;
        zwiftObj = z_innsbruck;
        mapTiles = [];
        d3.select('#map3d').style('background', '#69892A');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_yorkshire.v_north &&
        segment.latLngArr2[0].lat > z_yorkshire.v_south &&
        segment.latLngArr2[0].lng < z_yorkshire.v_east &&
        segment.latLngArr2[0].lng > z_yorkshire.v_west) {

        isZwift = true;
        zwiftObj = z_yorkshire;
        mapTiles = [];
        d3.select('#map3d').style('background', '#69892A');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_critcity.v_north &&
        segment.latLngArr2[0].lat > z_critcity.v_south &&
        segment.latLngArr2[0].lng < z_critcity.v_east &&
        segment.latLngArr2[0].lng > z_critcity.v_west) {

        isZwift = true;
        zwiftObj = z_critcity;
        mapTiles = [];
        d3.select('#map3d').style('background', '#69892A');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_france.v_north &&
        segment.latLngArr2[0].lat > z_france.v_south &&
        segment.latLngArr2[0].lng < z_france.v_east &&
        segment.latLngArr2[0].lng > z_france.v_west) {

        isZwift = true;
        zwiftObj = z_france;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_italy.v_north &&
        segment.latLngArr2[0].lat > z_italy.v_south &&
        segment.latLngArr2[0].lng < z_italy.v_east &&
        segment.latLngArr2[0].lng > z_italy.v_west) {

        isZwift = true;
        zwiftObj = z_italy;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }
    if (lm_ZwiftMapsMarker && segment.latLngArr2[0].lat < z_champs.v_north &&
        segment.latLngArr2[0].lat > z_champs.v_south &&
        segment.latLngArr2[0].lng < z_champs.v_east &&
        segment.latLngArr2[0].lng > z_champs.v_west) {

        isZwift = true;
        zwiftObj = z_champs;
        mapTiles = [];
        d3.select('#map3d').style('background', '#3A85DB');
    }

    //var map3dzoom = map3.zoom;
    var map3dtiles = Math.max(2, Math.floor(parseInt(d3.select('#map3d').style('width')) / 256) + (getParameterByName('t') != '' ? parseInt(getParameterByName('t')) : 2));
    var latExt1 = d3.extent(segment.latLngArr2, function(d) {
        return d.lat
    }).sort(d3.ascending);
    var lngExt1 = d3.extent(segment.latLngArr2, function(d) {
        return d.lng
    }).sort(d3.ascending);
    for (var i = 18; i > 1; i--) {
        if (map3dtiles > Math.max(Math.abs(long2tile(lngExt1[0], i) - long2tile(lngExt1[1], i)), Math.abs(lat2tile(latExt1[0], i) - lat2tile(latExt1[1], i)))) {
            map3dzoom = i - 0; //1
            i = 0;
        }
    }
    map3ddrawn = true;
    var latExt = d3.extent(segment.latLngArr2, function(d) {
        return d.lat
    }).map(function(d) {
        return lat2tile(d, map3dzoom)
    }).sort(d3.ascending);
    var lngExt = d3.extent(segment.latLngArr2, function(d) {
        return d.lng
    }).map(function(d) {
        return long2tile(d, map3dzoom)
    }).sort(d3.ascending);

    var mapTiles = [];
    var mtd = [];

    var activeMapTile = mapTileObjs.filter(function(d) {
        return d.key == getCookie('lmap')
    });

    if (getCookie('lmap') == 'osuk') {
        var tileFunc = function(coor, zoom) {
            return svMap.mapTypes.osuk.getTile(coor, zoom, document)
        };
    } else {
        if (activeMapTile.length == 0) {
            activeMapTile = mapTileObjs[0];
        } else {
            activeMapTile = activeMapTile[0];
        }
        var tileFunc = activeMapTile.tile;
    }
    for (var i = lngExt[0] - tilePadding.W; i <= lngExt[1] + tilePadding.E; i++) {
        for (var j = latExt[0] - tilePadding.N; j <= latExt[1] + tilePadding.S; j++) {
            mapTiles.push(tileFunc({
                x: i,
                y: j
            }, map3dzoom));
            mtd.push([map3dzoom, i, j]);
        }
    }

    mtxExt = d3.extent(mtd, function(d) {
        return d[1]
    });
    mtyExt = d3.extent(mtd, function(d) {
        return d[2]
    });
    var xScale = d3.scale.linear().domain(d3.range(mtxExt[0], mtxExt[1] + 2).map(function(d) {
        return tile2long(d, mtd[0][0])
    })).range(d3.range(0, (mtxExt[1] - mtxExt[0] + 2) * svTileSize, svTileSize));
    var yScale = d3.scale.linear().domain(d3.range(mtyExt[0], mtyExt[1] + 2).map(function(d) {
        return tile2lat(d, mtd[0][0])
    })).range(d3.range(0, (mtyExt[1] - mtyExt[0] + 2) * svTileSize, svTileSize));

    var ld = segment.latLngArr2.map(function(d, i) {
        var r = {};
        r.i = i;
        r.lng = d.lng;
        r.lat = d.lat;
        r.x = xScale(d.lng);
        r.y = yScale(d.lat);
        r.z = segment.elevationArr2[i];
        r.d = segment.distanceArr2[i];
        return r;
    });

    var zExt = d3.extent(ld, function(d) {
        return d.z
    });

    var tileLen = distLatLon(xScale.domain()[0], yScale.domain()[0], xScale.domain()[1], yScale.domain()[1]);

    var zScale = d3.scale.linear().domain(zExt).range([10, 10 + ((zExt[1] - zExt[0]) * (250 * elevMult * 1.5) / tileLen)]);

    var smoothed = filterData(ld.map(function(d) {
        return {
            x: d.d,
            y: d.z
        }
    }));
    ld.forEach(function(d, i) {
        d.z = smoothed[i].ySmooth;
    });

    var ld2 = ld;
    var simpVal = 10;
    if (ld2.length >= map3dsimplifyLimit) {
        ld2 = simplify(ld, simpVal, true);
        while (ld2.length < map3dsimplifyLimit && simpVal > 0.01) {
            ld2 = simplify(ld, simpVal, false);
            simpVal = simpVal / 2;
        }
    }

    ld2 = ld2.map(function(d, i) {
        var r = d;
        r.dd = i == ld2.length - 1 ? 0 : segment.distanceArr2[ld2[i + 1].i] - segment.distanceArr2[r.i];
        r.dx = i == ld2.length - 1 ? 0 : ld2[i + 1].x - r.x;
        r.dy = i == ld2.length - 1 ? 0 : ld2[i + 1].y - r.y;
        r.z1 = zScale(r.z);
        r.z2 = i == ld2.length - 1 ? 0 : zScale(ld2[i + 1].z);
        r.zd = i == ld2.length - 1 ? 0 : ld2[i + 1].z - r.z;
        r.td = Math.sqrt(r.dx * r.dx + r.dy * r.dy) + 1;
        r.b = i == ld2.length - 1 ? 0 : Math.atan2(d.dy, d.dx) * 180 / Math.PI;
        r.b = (r.b + (10 * 360)) % 360;
        r.g = r.zd / r.dd;
        r.c = isZwift && v_color != null ? v_color : colScale2(r.g);
        r.c2 = d3.rgb(d.c);
        return r;
    });

    xxExt = d3.extent(ld2, function(d) {
        return d.x
    });
    yyExt = d3.extent(ld2, function(d) {
        return d.y
    });

    d3.select('#map3d')
        .style('height', (window.innerHeight - document.getElementById('map3d').getBoundingClientRect().top) + 'px');

    var to = (xxExt[0] + (xxExt[1] - xxExt[0]) / 2) + 'px ' + (yyExt[0] + (yyExt[1] - yyExt[0]) / 2) + 'px';

    d3.select('#map3dWrapper')
        .style('-webkit-perspective-origin', to)
        .style('-moz-perspective-origin', to)
        .style('perspective-origin', to);

    d3.select('#map3dContent').selectAll('*').remove();

    if (isZwift) {
        d3.select('#map3dContent')
            .style({
                'position': 'absolute',
                'background-color': 'transparent',
                'height': ((mtyExt[1] - mtyExt[0] + 1) * svTileSize) + 'px',
                '-webkit-transform-origin': to,
                '-moz-transform-origin': to,
                'transform-origin': to
            })
            .append('div')
            .style({
                'position': 'absolute',
                'background-color': 'transparent',
                'width': (xScale(zwiftObj.v_east) - xScale(zwiftObj.v_west)) + 'px',
                'height': (yScale(zwiftObj.v_south) - yScale(zwiftObj.v_north)) + 'px',
                'overflow': 'visible'
            })
            .append('img')
            .attr('src', zwiftObj.v_url)
            .style({
                'position': 'absolute',
                'top': function(d) {
                    return yScale(zwiftObj.v_north) + 'px'
                },
                'left': function(d) {
                    return xScale(zwiftObj.v_west) + 'px'
                },
                'height': function(d) {
                    return (yScale(zwiftObj.v_south) - yScale(zwiftObj.v_north)) + 'px'
                },
                'width': function(d) {
                    return (xScale(zwiftObj.v_east) - xScale(zwiftObj.v_west)) + 'px'
                }
            });
    } else {
        d3.select('#map3dContent')
            .style({
                'position': 'absolute',
                'background-color': 'transparent',
                'height': ((mtyExt[1] - mtyExt[0] + 1) * svTileSize) + 'px',
                '-webkit-transform-origin': to,
                '-moz-transform-origin': to,
                'transform-origin': to
            })
            .append('svg')
            /*    .attr({
                   'xmlns': 'http://www.w3.org/2000/svg',
                   'xmlns:xlink': 'http://www.w3.org/1999/xlink'
                })*/
            .style({
                'position': 'absolute',
                'background-color': 'transparent',
                'width': ((mtxExt[1] - mtxExt[0] + 1) * svTileSize) + 'px',
                'height': ((mtyExt[1] - mtyExt[0] + 1) * svTileSize) + 'px'
            })
            .selectAll(getCookie('lmap') == 'osuk' ? 'svg.osmaptile' : 'image')
            .data(mapTiles)
            .enter()
            .append(getCookie('lmap') == 'osuk' ? 'svg' : 'image')
            .classed('osmaptil', getCookie('lmap') == 'osuk')
            .style({
                'position': 'absolute',
                'width': svTileSize + 'px',
                'height': svTileSize + 'px'
            })
            .attr({
                'x': function(d, i) {
                    return svTileSize * (mtd[i][1] - mtxExt[0])
                },
                'y': function(d, i) {
                    return svTileSize * (mtd[i][2] - mtyExt[0])
                },
                'width': svTileSize + 'px',
                'height': svTileSize + 'px'
            }).each(function(d) {
                if (getCookie('lmap') == 'osuk') {
                    this.appendChild(d);
                } else {
                    d3.select(this).attr('xlink:href', d);
                }
            });
    }

    d3.select('#map3dContent')
        .selectAll('svg.p').remove();

    var svgp = d3.select('#map3dContent')
        .selectAll('svg.p')
        .data(ld2.slice(0, ld2.length - 1))
        .enter()
        .append('svg')
        .attr('class', function(d, i) {
            return 'p map3ditem' + i
        })
        .style({
            'position': 'absolute',
            'top': function(d) {
                return d.y + 'px'
            },
            'left': function(d) {
                return d.x + 'px'
            },
            'height': function(d) {
                return (Math.max(d.z1, d.z2) + 2) + 'px'
            },
            'width': function(d) {
                return d.td + 'px'
            },
            '-webkit-transform': function(d) {
                return 'rotateX(90deg) rotateY(' + d.b + 'deg)'
            },
            '-moz-transform': function(d) {
                return 'rotateX(90deg) rotateY(' + d.b + 'deg)'
            },
            'transform': function(d) {
                return 'rotateX(90deg) rotateY(' + d.b + 'deg)'
            },
            'background': 'transparent',
            '-webkit-transform-origin': '0px 0px',
            '-moz-transform-origin': '0px 0px',
            'transform-origin': '0px 0px'
        });

    svgp.append('polygon')
        .classed('grad', true)
        .attr('points', function(d) {
            return '0,0 ' + d.td + ',0 ' + d.td + ',' + d.z2 + ' 0,' + d.z1
        })
        .attr('style', function(d) {
            return 'opacity:0.8;fill:' + d.c + ';stroke-width:0px;stroke:' + d.c2.darker().toString();
        });
    /*.append("svg:title")
        .text(function(d, i) { return "Gradient " + f1dp(100*d.g)+'%'; });;*/
    svgp.append('polygon')
        .classed('road', true)
        .attr('points', function(d) {
            return d.td + ',' + (d.z2 + 1) + ' 0,' + (d.z1 + 1)
        })
        .attr('style', function(d) {
            return 'opacity:0.8;fill:transparent;stroke-width:2px;stroke:' + (isZwift && v_colorRoad != null ? v_colorRoad : '#444');
        });

    if (isFirst) {
        d3.select('#map3d')
            .on('mousedown', function(e) {
                d3.select('#map3d')
                    .on('mousemove', function(f) {
                        if (d3.event.which == 1) {
                            handleMove3d2(this, d3.mouse(this), 'mouse');
                        } else {
                            d3.select('#map3d')
                                .on('mousemove', null);
                            dragX2 = null;
                            dragY2 = null;
                        }
                        d3.event.preventDefault();
                    });
            })
            .on('mouseup', function() {
                d3.select('#map3d')
                    .on('mousemove', null);
                dragX2 = null;
                dragY2 = null;
                d3.event.preventDefault();
            })
            .on('touchstart', function(e) {
                d3.select('#map3d')
                    .on('touchmove', function(f) {
                        handleMove3d2(this, d3.touches(this), 'touch');
                        d3.event.preventDefault();
                    });
                d3.event.preventDefault();
            })
            .on('touchend', function() {
                d3.select('#map3d')
                    .on('mousemove', null);
                dragX2 = null;
                dragY2 = null;

                d3.event.preventDefault();
            });
        addEvent(window, "resize", function(event) {
            map3dcentre();
        });
    }
    map3dcentre();
    map3dshade();
}

var spinXVal2 = 0,
    spinYVal2 = 45,
    dragX2, dragY2, map3dMoveTimer;
var map3dPadding = {
    "top": window.innerHeight / 20 + 20,
    "bottom": window.innerHeight / 20,
    "left": window.innerWidth / 20,
    "right": window.innerWidth / 20
};

function map3dcentre() { //resetPadding
    /*if (typeof(resetPadding)==='undefined' || resetPadding) {
        map3dPadding = {
            "top": window.innerHeight / 20 + 20,
            "bottom": window.innerHeight / 20,
            "left": window.innerWidth / 20,
            "right": window.innerWidth / 20
        };
    }*/
    d3.select('#map3dScale').style('transform', null);
    //var marginLeft = (2 * (xxExt[0] + (xxExt[1] - xxExt[0]) / 2) - parseInt(d3.select('#map3d').style('width'))) / 2; //(aw - (xxExt[1]-xxExt[0]))/2; //tilePadding * 250 - 250;
    var map3doffsetTop = document.getElementById('map3d').getBoundingClientRect().top;
    var map3doffsetLeft = document.getElementById('map3d').getBoundingClientRect().left;
    var map3doffsetRight = document.getElementById('map3d').getBoundingClientRect().right;
    var rects = d3.selectAll('#map3d .p')[0].map(function(d) {
        return d.getBoundingClientRect()
    });
    var minTop = d3.min(rects, function(d) {
        return d.top
    });
    var maxBottom = d3.max(rects, function(d) {
        return d.bottom
    });
    var minLeft = d3.min(rects, function(d) {
        return d.left
    });
    var maxRight = d3.max(rects, function(d) {
        return d.right
    });
    var vScale = ((window.innerHeight - map3doffsetTop - map3dPadding.top - map3dPadding.bottom) / (maxBottom - minTop));
    var hScale = ((parseInt(d3.select('#map3d').style('width')) - map3dPadding.left - map3dPadding.right) / (maxRight - minLeft));
    d3.select('#map3dScale').style('transform', 'scale(' + Math.min(vScale, hScale) + ')').style('top', '0px').style('left', '0px');
    var minTop = d3.min(d3.selectAll('#map3d .p')[0].map(function(d) {
        return d.getBoundingClientRect().top
    }));
    var maxBottom = d3.max(d3.selectAll('#map3d .p')[0].map(function(d) {
        return d.getBoundingClientRect().bottom
    }));
    //  var marginTop = parseInt(d3.select('#map3dWrapper').style('top')) - ((minTop - map3doffsetTop) - ((minTop - map3doffsetTop) + (window.innerHeight - maxBottom)) / 2);
    //  var marginTop = -1 * (minTop - map3doffsetTop) + parseInt(d3.select('#map3dWrapper').style('top')) + padding.top;
    var marginTop = (-1 * (minTop - ((window.innerHeight - document.getElementById('map3d').getBoundingClientRect().top) - (maxBottom - minTop)) / 2 - document.getElementById('map3d').getBoundingClientRect().top));
    var minLeft = d3.min(d3.selectAll('#map3d .p')[0].map(function(d) {
        return d.getBoundingClientRect().left
    }));
    var maxRight = d3.max(d3.selectAll('#map3d .p')[0].map(function(d) {
        return d.getBoundingClientRect().right
    }));
    var marginLeft = parseInt(d3.select('#map3dWrapper').style('left')) - ((minLeft - map3doffsetLeft) - ((minLeft - map3doffsetLeft) + (map3doffsetRight - maxRight)) / 2);
    d3.select('#map3dScale').style('top', marginTop + 'px').style('left', marginLeft + 'px');
    //d3.select('#map3dWrapper').style('left', marginLeft + 'px');
}

function map3dshade() {
    var mapAngle = (spinXVal2 + 100 * 360) % 360;
    d3.selectAll('#map3dContent .p .grad').each(function(d) {
        var displayAngle = (d.b + mapAngle + 2 * 360) % 360;
        displayAngle = (displayAngle > 90 && displayAngle <= 270 ? displayAngle - 180 : displayAngle);
        var e = Math.sin(deg2rad(displayAngle));
        d3.select(this).style({
            'fill': d.c2.darker(e),
            'stroke': d.c2.darker(0.5 + e)
        })
    });
}

function handleMove3d2(obj, mouseTouch, type) {
    if (type == 'touch') {
        mouseTouch = mouseTouch[0];
    }

    var l_dragX = mouseTouch[0];
    var l_dragY = mouseTouch[1];

    l_dragX = 2 * 360 * l_dragX / parseInt(d3.select('#map3d').style('width'));
    l_dragY = 2 * 360 * l_dragY / parseInt(d3.select('#map3d').style('height'));

    if (dragX2 != null && spinYVal + dragY2 - l_dragY <= 0) {
        spinXVal2 += dragX2 - l_dragX;
        spinYVal2 += dragY2 - l_dragY;
        spinYVal2 = Math.max(Math.min(spinYVal2, 90), 0);
    }

    dragX2 = l_dragX;
    dragY2 = l_dragY;
    //console.debug('x: ' + mouseTouch[0] + ', y: ' + mouseTouch[1] + ', xChange: ' + xChange + ', yChange: ' + yChange + 'spinXVal: ' + spinXVal2 + ', spinYVal: ' + spinYVal2);

    gmapSetRotation();
}

function gmapSetRotation() {
    d3.select('#map3dContent')
        .style('-webkit-transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)')
        .style('-moz-transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)')
        .style('transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)');

    //map3dshade();

    window.clearTimeout(map3dMoveTimer);
    map3dMoveTimer = window.setTimeout(map3dcentre, 500);
}

var polys = d3.selectAll('#map3dContent svg.p .grad').style('opacity', 0)[0];
var polys2 = d3.selectAll('#map3dContent svg.p .road').style('opacity', 0)[0];
var polysGradOpacity = 0.7;
var polysRoadOpacity = 0.7;
var polyI = 0;
var v_colorRoad = null;
var v_color = null;
/*if (getParameterByName('color') != '') {
    v_color = '#' + getParameterByName('color');
    v_colorRoad = d3.rgb(v_color).darker(2).toString();
}*/
function polyAnimate2() {
    if (polyI >= polys.length) {
        polyI = 0;
        //window.setTimeout(polyAnimate, 500);
    } else {
        d3.select(polys[polyI]).style('opacity', 1)
            .transition().style('opacity', polysGradOpacity).duration(500);
        d3.select(polys2[polyI]).style('opacity', 1).style('stroke-width', '5')
            .transition().style('opacity', polysRoadOpacity).style('stroke-width', '2').duration(500);
        polyI++;
        window.setTimeout(polyAnimate2, 10);
    }
}

function polyAnimate() {
    polys = d3.selectAll('#map3dContent svg.p .grad').style('opacity', 0)[0];
    polys2 = d3.selectAll('#map3dContent svg.p .road').style('opacity', 0)[0];
    polyI = 0;
    window.setTimeout(polyAnimate2, 1000);
}
var spin3dtimer = null;

function spin3dmap(angle, delay) {
    spinXVal2 += angle;
    d3.select('#map3dContent')
        .style('-webkit-transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)')
        .style('-moz-transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)')
        .style('transform', 'rotateX(' + spinYVal2 + 'deg) rotateZ(' + spinXVal2 + 'deg)');

    spin3dtimer = window.setTimeout(function() { spin3dmap(angle, delay) }, delay);
}

var kmzImages = [];

function kmzSetIconHref() {
    xmlDataObj.waypoints.forEach(function(d) {
        // looking to see if any images already exist
        var s, sm = jsonObj.kml.Document.StyleMap.filter(function(e) { return e._id.indexOf(d.styleUrl.replace('#', '')) == 0 });
        if (sm.length > 0) {
            s = jsonObj.kml.Document.Style.filter(function(e) { return e._id.indexOf(sm[0].Pair[0].styleUrl.replace('#', '')) == 0 });
        } else {
            s = jsonObj.kml.Document.Style.filter(function(e) { return e._id.indexOf(d.styleUrl.replace('#', '')) == 0 });
        }
        if (s.length > 0) {
            d.icon = kmzImages.filter(function(e) {
                return s[0].IconStyle && e[0].indexOf(s[0].IconStyle.Icon.href) == 0
            });
        }
    });
}

function getLatLngFromXML(xmlData) {
    var a = { name: '', routes: [], waypoints: [] };
    //jsonObj = JSON.parse(xml2json(parseXml(xmlData.replace(/(<name>|<desc>|<description>)[\s\n]*<\!\[CDATA\[([^\]]*)\]\]>[\s\n]*(<\/name>|<\/desc>|<\/description>)/g, '$1$2$3').replace(/[a-zA-Z]*:[a-zA-Z]*="[^"]*"/g, '').replace(/([</])[a-zA-Z]*:/g, '$1'))).replace(/undefined/g, ''));
    jsonObj = JSON.parse(xml2json(parseXml(xmlData.replace(/[a-zA-Z]*:[a-zA-Z]*="[^"]*"/g, '').replace(/([</])[a-zA-Z]*:/g, '$1'))).replace(/undefined/g, ''));

    if (typeof(jsonObj.kml) !== 'undefined') {
        // kml file
        if (!jsonObj.kml.Document && jsonObj.kml.Folder && jsonObj.kml.Folder.Document) {
            jsonObj.kml.Document = jsonObj.kml.Folder.Document;
        }
        if (typeof(jsonObj.kml.Document.name) !== 'undefined') {
            a.name = jsonObj.kml.Document.name.toString();
        }
        var folder = [jsonObj.kml.Document];
        if (typeof(jsonObj.kml.Document.Folder) !== 'undefined') {
            folder = typeof(jsonObj.kml.Document.Folder.length) === 'undefined' ? [jsonObj.kml.Document.Folder] : jsonObj.kml.Document.Folder;
            if (typeof(jsonObj.kml.Document.Document) !== 'undefined') {
                var doc = typeof(jsonObj.kml.Document.Document.length) === 'undefined' ? [jsonObj.kml.Document.Document] : jsonObj.kml.Document.Document;
                folder = d3.merge([folder, d3.merge(doc.map(function(d) {
                    return typeof(d.Folder.length) === 'undefined' ? [d.Folder] : d.Folder;
                }))]);
            }
            folder = d3.merge([folder, d3.merge(folder.map(function(d) { return typeof(d.Folder) === 'undefined' ? [d] : (typeof(d.Folder.length) === 'undefined' ? [d.Folder] : d.Folder) }))]);
        }
        folder.forEach(function(d, i) {
            var placemark = typeof(d.Placemark) === 'undefined' ? [] : (typeof(d.Placemark.length) === 'undefined' ? [d.Placemark] : d.Placemark);
            placemark.forEach(function(e) {
                if (typeof(e.MultiGeometry) !== 'undefined') {
                    var linestrings = typeof(e.MultiGeometry.LineString.length) === 'undefined' ? [e.MultiGeometry.LineString] : e.MultiGeometry.LineString;
                    var ls = d3.merge(linestrings.map(function(f) {
                        return f.coordinates.replaceAll(/\n/g, ' ').trim().split(/\s+/).map(function(f) {
                            var o = f.split(',');
                            return {
                                lat: +o[1],
                                lng: +o[0],
                                ele: +o[2]
                            }
                        });
                    }));
                    var o = {
                        name: typeof(e.name) === 'undefined' ? 'Route ' + i : e.name.toString(),
                        lle: ls
                    }
                    a.routes.push(o);
                }
                if (typeof(e.LineString) !== 'undefined') {
                    var o = {
                        name: typeof(e.name) === 'undefined' ? 'Route ' + i : e.name.toString(),
                        lle: e.LineString.coordinates.replaceAll(/\n/g, ' ').trim().split(/\s+/).map(function(f) {
                            var o = f.split(',');
                            return {
                                lat: +o[1],
                                lng: +o[0],
                                ele: +o[2]
                            }
                        })
                    }
                    a.routes.push(o);
                }
                if (typeof(e.Track) !== 'undefined' && typeof(e.Track) !== 'undefined' && typeof(e.Track.coord) !== 'undefined') {
                    var o = {
                        name: typeof(e.name) === 'undefined' ? (typeof(e.description) === 'undefined' ? 'Route ' + i : e.description.toString()) : e.name.toString(),
                        lle: e.Track.coord.map(function(f) {
                            var o = f.split(' ');
                            return {
                                lat: +o[1],
                                lng: +o[0],
                                ele: +o[2]
                            }
                        })
                    }
                    a.routes.push(o);
                }
                if (typeof(e.Point) !== 'undefined') {
                    var coor = e.Point.coordinates.replaceAll(/\n/g, ' ').trim().split(',');
                    var o = {
                        name: (typeof(e.name) !== 'undefined' && e.name != null ? e.name.toString() : (typeof(e.description) !== 'undefined' && e.description != null ? e.description.toString() : (typeof(e.styleUrl) !== 'undefined' ? e.styleUrl.toString() : 'Waypoint ' + i))),
                        desc: typeof(e.description) !== 'undefined' && e.description != null ? e.description.toString() : '',
                        lat: +coor[1],
                        lng: +coor[0],
                        styleUrl: typeof(e.styleUrl) !== 'undefined' ? e.styleUrl.toString() : ''
                    }
                    a.waypoints.push(o);
                }
            });
        });
    }

    if (typeof(jsonObj.gpx) !== 'undefined') {
        if (typeof(jsonObj.gpx.metadata) !== 'undefined' && typeof(jsonObj.gpx.metadata.name) !== 'undefined') {
            a.name = jsonObj.gpx.metadata.name.toString();
        }
        if (typeof(jsonObj.gpx.rte) !== 'undefined') {
            // gpx route
            var rte = typeof(jsonObj.gpx.rte.length) === 'undefined' ? [jsonObj.gpx.rte] : jsonObj.gpx.rte;
            rte.forEach(function(d, i) {
                var o = {
                    name: typeof(d.name) === 'undefined' || d.name == null ? 'Route ' + i : d.name.toString(),
                    lle: []
                }
                try {
                    o.colour = d.extensions.RouteExtension.DisplayColor.__text;
                } catch (e) {
                    o.colour = null;
                }

                var rtept = typeof(d.rtept.length) === 'undefined' ? [d.rtept] : d.rtept;
                rtept.forEach(function(e, j) {
                    if (typeof(e.extensions) !== 'undefined' && typeof(e.extensions.RoutePointExtension) !== 'undefined' && typeof(e.extensions.RoutePointExtension.rpt) !== 'undefined') {
                        var rpt = typeof(e.extensions.RoutePointExtension.rpt.length) === 'undefined' ? [e.extensions.RoutePointExtension.rpt] : e.extensions.RoutePointExtension.rpt;
                        rpt.forEach(function(f) {
                            if (o.lle.length == 0 || o.lle.last()._lat != +f._lat || o.lle.last().lng != +f._lon) {
                                o.lle.push({ lat: +f._lat, lng: +f._lon, ele: typeof(f.ele) !== 'undefined' ? +f.ele : 0 });
                            }
                        });
                    } else {
                        o.lle.push({ lat: +e._lat, lng: +e._lon, ele: typeof(e.ele) !== 'undefined' ? +e.ele : 0 });
                    }
                });
                a.routes.push(o);
            });
            // check for waypoints
            if (typeof(jsonObj.gpx.wpt) !== 'undefined') {
                var wpt = typeof(jsonObj.gpx.wpt.length) === 'undefined' ? [jsonObj.gpx.wpt] : jsonObj.gpx.wpt;
                wpt.forEach(function(d, i) {
                    var o = {
                        name: typeof(d.name) === 'undefined' || d.name == null ? (typeof(d.desc) === 'undefined' || d.desc == null ? 'Waypoint ' + i : d.desc.toString()) : d.name.toString(),
                        lat: d._lat,
                        lng: d._lon
                    }
                    a.waypoints.push(o);
                });
            }
        }
        if (typeof(jsonObj.gpx.trk) !== 'undefined') {
            // gpx track
            var trk = typeof(jsonObj.gpx.trk.length) === 'undefined' ? [jsonObj.gpx.trk] : jsonObj.gpx.trk;
            trk.forEach(function(d, i) {
                var o = {
                    name: typeof(d.name) === 'undefined' || d.name == null ? 'Route ' + i : d.name.toString(),
                    lle: []
                }
                var trkpt;
                if (typeof(d.trkseg.length) !== 'undefined') {
                    trkpt = d3.merge(d.trkseg.map(function(d) { return d.trkpt }))
                } else {
                    trkpt = typeof(d.trkseg.trkpt.length) === 'undefined' ? [d.trkseg.trkpt] : d.trkseg.trkpt;
                }
                trkpt.forEach(function(e, j) {
                    o.lle.push({ lat: +e._lat, lng: +e._lon, ele: typeof(e.ele) !== 'undefined' ? +e.ele : 0 });
                });
                a.routes.push(o);
            });
            // check for waypoints
            if (typeof(jsonObj.gpx.wpt) !== 'undefined') {
                var wpt = typeof(jsonObj.gpx.wpt.length) === 'undefined' ? [jsonObj.gpx.wpt] : jsonObj.gpx.wpt;
                wpt.forEach(function(d, i) {
                    var o = {
                        name: typeof(d.name) === 'undefined' || d.name == null ? (typeof(d.desc) === 'undefined' || d.desc == null ? 'Waypoint ' + i : d.desc.toString()) : d.name.toString(),
                        lat: d._lat,
                        lng: d._lon
                    }
                    a.waypoints.push(o);
                });
            }
        }
    }
    return a;
}

function drawWaypoints() {
    xmlDataObj.waypoints.forEach(function(d) {
        if (d.icon && d.icon.length > 0) {
            d.marker = new google.maps.Marker({
                position: new google.maps.LatLng(d.lat, d.lng),
                zIndex: 20,
                map: svMap,
                draggable: false,
                icon: {
                    url: d.icon[0][1],
                    anchor: new google.maps.Point(-1, -1),
                    scaledSize: new google.maps.Size(25, 25)
                },
                title: d.name
            });
            d.markerDot = new google.maps.Marker({
                position: new google.maps.LatLng(d.lat, d.lng),
                zIndex: 15,
                map: svMap,
                icon: {
                    path: google.maps.SymbolPath.CIRCLE,
                    fillOpacity: 0.8,
                    fillColor: '#000',
                    strokeOpacity: 0,
                    scale: 2 //pixels
                }
            });
        } else {
            d.marker = new google.maps.Marker({
                position: new google.maps.LatLng(d.lat, d.lng),
                zIndex: 20,
                map: svMap,
                draggable: false,
                title: d.name
            });
        }
    });
}
