Skip to content

Instantly share code, notes, and snippets.

@natchiketa
Created April 23, 2013 22:19
Show Gist options
  • Save natchiketa/5447904 to your computer and use it in GitHub Desktop.
Save natchiketa/5447904 to your computer and use it in GitHub Desktop.
Uses Google Maps API v3 to pan between to LatLng coordinates based on the scroll position of the page.
/*
Global
*/
var map, origin, destination,
scrollTop, lastScrollTop,
percentScrollTop, lastPercentScrollTop,
heading, lastHeading,
planeOffset, planeOffsetDiff, lastPlaneOffset;
var CITIES = {
'Amsterdam': {
lat: 52.373056, lng: 4.892222
},
'Sydney': {
lat: -33.859972, lng: 151.211111
}
}
var VLUCHTPUNTEN = {
startY: 219,
runway: 788,
rtMargin: 1450,
endX: 1040,
endY: -685
};
var VLUCHT = function() {
return [
{
pos: 2,
easeIn: 2,
easeOut: 2,
offsets: {
before: {left: this.runway, top: this.startY},
at: {left: this.runway, top: this.startY},
after: {left: this.runway, top: this.startY}
},
origin: true
},
{
pos: 4.5,
easeIn: 2,
easeOut: 2.5,
offsets: {
before: {left: this.runway, top: this.startY},
at: {left: (this.runway + this.rtMargin) / 2, top: this.startY},
after: {left: this.rtMargin - 5, top: this.startY}
}
},
{
pos: 10.5,
easeIn: 4,
easeOut: 10,
offsets: {
before: {left: this.rtMargin - 5, top: this.startY},
at: {left: this.rtMargin, top: this.startY},
after: {left: this.rtMargin, top: this.startY}
}
},
{
pos: 40.5,
easeIn: 20,
easeOut: 20,
offsets: {
before: {left: this.rtMargin, top: this.startY},
at: {left: this.rtMargin, top: this.startY},
after: {left: this.rtMargin - 5, top: this.startY}
}
},
{
pos: 67.5,
easeIn: 7,
easeOut: 17.5,
offsets: {
before: {left: this.rtMargin - 5, top: this.startY},
at: {left: this.endX, top: this.startY},
after: {left: this.endX, top: this.endY}
},
destination: true
}
];
};
VLUCHT = _.bind(VLUCHT, VLUCHTPUNTEN)();
function cityLatLng(name) {
return new google.maps.LatLng(CITIES[name].lat, CITIES[name].lng)
}
function interpolateLatLng(origName, destName, percent, max) {
var ilat, ilng;
var orig = CITIES[origName];
var dest = CITIES[destName];
// If, for whatever reason, we want to have the interpolation calculated from 0 to
// a value other than 100, the `max` argument can be specified.
var divisor = _.isUndefined(max) ? 100 : max;
var taperedOrig = {
lat: _.isEqual(0, divisor)
? orig.lat
: orig.lat - (orig.lat * ((1 / divisor) * Math.min(percent, max))).floor(6),
lng: _.isEqual(0, divisor)
? orig.lng
: orig.lng - (orig.lng * ((1 / divisor) * Math.min(percent, max))).floor(6)
};
var taperedDest = {
lat: _.isEqual(0, divisor)
? dest.lat
: (dest.lat * ((1 / divisor) * Math.min(percent, max))).floor(6),
lng: _.isEqual(0, divisor)
? dest.lng
: (dest.lng * ((1 / divisor) * Math.min(percent, max))).floor(6)
};
//console.log(taperedOrig, taperedDest);
ilat = taperedOrig.lat + taperedDest.lat;
ilng = taperedOrig.lng + taperedDest.lng;
// var args = Array.prototype.slice.call(arguments);
// console.log('lat: ', ilat, ', lng: ', ilng, '\targuments: [', args.join(', '), ']');
return new google.maps.LatLng(ilat, ilng);
}
function roundedOffset(offset, nearest) {
return _.isUndefined(nearest)
? { left: (offset.left).round(), top: (offset.top).round()}
: { left: (offset.left / nearest).round() * nearest, top: (offset.top / nearest).round() * nearest }
}
function movePlane() {
if (percentScrollTop == 0 || _.isUndefined(percentScrollTop)) {
var origin = _.find(VLUCHT, function(vector) {
return _.has(vector, 'origin') && vector.origin === true;
});
if (origin) {
$('#plane')
.css(origin.offsets.at)
.rotate(0);
}
return;
}
_.each(VLUCHT, function(vector) {
var before = percentScrollTop < vector.pos && vector.pos - percentScrollTop <= vector.easeIn;
var after = percentScrollTop > vector.pos && percentScrollTop <= vector.pos + vector.easeOut;
// console.log('before: ', before?'true':'false', 'after: ', after?'true':'false');
if (before === false && after === false) {
$('#plane').removeClass('arrived on_runway');
return;
}
$('#plane').toggleClass('on_runway', vector.destination && after);
$('#plane').toggleClass('arrived', vector.destination && after);
var target = before ? vector.offsets.before : vector.offsets.after;
var easePos = before
? (1 / vector.easeIn) * (vector.pos - percentScrollTop)
: (1 / vector.easeOut) * (percentScrollTop - vector.pos);
planeOffsetDiff = {
left: target.left - vector.offsets.at.left,
top: target.top - vector.offsets.at.top
};
console.log('target: ', before ? 'before' : after ? 'after' : 'n/a');
console.log('vector.pos: ', vector.pos, '\tpercentScrollTop: ', percentScrollTop);
console.log('planeOffsetDiff: ', planeOffsetDiff);
console.log('easePos: ', easePos);
var newOffset = {
left: vector.offsets.at.left + (planeOffsetDiff.left * easePos),
top: vector.offsets.at.top + (planeOffsetDiff.top * easePos)
};
planeOffset = newOffset;
if (Modernizr.csstransforms) {
$('#plane').css(planeOffset);
} else {
$('#plane').animate(planeOffset, 75);
}
// Rotation based on movement
// lastHeading = _.isUndefined(heading) ? 0 : heading;
var curOff = _.extend(planeOffset, {top: $('#plane').offset().top});
var lastOff = lastPlaneOffset || curOff;
// console.log('curOff: ', curOff);
// console.log('lastOff: ', lastOff);
var deltaY = curOff.top - lastOff.top;
var deltaX = curOff.left - lastOff.left;
// console.log('deltaY: ', deltaY);
// console.log('deltaX: ', deltaX);
deltaY = Math.abs(deltaY) < 2 ? 0 : deltaY;
deltaX = Math.abs(deltaX) < 2 ? 0 : deltaX;
// console.log('deltaY: ', deltaY);
// console.log('deltaX: ', deltaX);
heading = (Math.atan2(deltaY, deltaX) * (180 / Math.PI)) - 90;
var rndHeading = ((heading / 5).round()) * 5;
// console.log('Math.atan2(deltaY, deltaX): ', Math.atan2(deltaY, deltaX));
//
// console.log('heading: ', heading);
// console.log('rndHeading: ', rndHeading);
heading = rndHeading;
/*
if (curOff.left == lastOff.left) {
if (curOff.top > lastOff.top) {
rndHeading = 0;
}
if (curOff.top < lastOff.top) {
rndHeading = 180;
}
}
*/
$('#plane').rotate(heading);
lastPlaneOffset = _.extend(planeOffset, {top: $('#plane').offset().top});
});
}
function _wayPoint(event) {
lastScrollTop = scrollTop;
scrollTop = $(document).scrollTop();
percentScrollTop = (100 / $(document).height()) * scrollTop;
//console.log(percentScrollTop);
map.setCenter(interpolateLatLng('Amsterdam', 'Sydney', percentScrollTop, 60));
movePlane();
// Save the scroll position percentage and offset of the plane's DOM element
lastPercentScrollTop = percentScrollTop;
}
function initialize() {
/*
Basic Setup
*/
var myOptions = {
panControl: false,
zoomControl: false,
mapTypeControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
draggable: false,
disableDoubleClickZoom: true, //disable zooming
scrollwheel: false,
zoom: 6,
center: origin,
mapTypeId: google.maps.MapTypeId.ROADMAP // ROADMAP; SATELLITE; HYBRID; TERRAIN;
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}//end initialize
/*
onLoad
*/
$(function(){
// Size the Google Maps canvas to the window height, both on load and when the window is resized.
$(window).on('load resize', function(){
$('#canvas_holder')
.height($(this).height());
});
origin = cityLatLng('Amsterdam');
destination = cityLatLng('Sydney');
percentScrollTop = $(document).scrollTop();
movePlane();
initialize();
// Throttle the function which is called by the scroll event handler. Requires
// the Underscore library, or an Underscore-compatible equivalent, like Lodash.
var wayPoint = _.throttle(_wayPoint, 100);
$(window).on('scroll touchmove', function(event) {
wayPoint(event);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment