$(function() {
var map = null,
checkedIds = [],
//< list of tweet ids we've checked
appendedCount = 0,
//< number of tweets we successfully appended
searchTerm = "",
//< last search term
searching = false,
currentXhr = null,
//< an ajax request reference if we need to cancel
twitterButtonHtml = '<a href="https://twitter.com/share" class="twitter-share-button" data-count="vertical" data-via="ryanttb">Tweet</a><script src="//platform.twitter.com/widgets.js"></script>';
function initMap(center, zoom) {
// create a map using an optional center and zoom
map = $("#map").geomap({
center: center || [-71.0597732, 42.3584308],
zoom: zoom || 10,
// set the shapeStyle to a largish solid but translucent circle
// to give the tweets a heat map effect
shapeStyle: {
strokeOpacity: 0,
fillOpacity: .2,
width: "16px",
height: "16px",
borderRadius: "16px",
color: "#e44"
},
move: function(e, geo) {
// when the user moves, search for appended tweets
// and show a popup
// clear the popup
$("#popup").hide().html("");
if (searchTerm) {
// spatial query, geo has the cursor location as a map point
// this will find appended tweets within 3 pixels
var features = map.geomap("find", geo, 3),
popupHtml = "",
i = 0;
// for each tweet found, add some html to the popup
for (; i < features.length; i++) {
popupHtml += "<p>" + features[i].properties.tweet + "</p>";
}
if (popupHtml) {
// if any tweets found, show the popup
var $popup = $("#popup").append(popupHtml).css({
left: e.pageX,
top: e.pageY
});
var widthOver = $(window).width() - ($popup.width() + e.pageX),
heightOver = ($(window).height() - 32) - ($popup.height() + e.pageY),
left = e.pageX,
top = e.pageY;
if (widthOver < 0) {
left += widthOver;
}
if (heightOver < 0) {
top += heightOver;
}
$popup.css({
left: left,
top: top
}).show();
}
}
}
});
if (searchTerm && !searching) {
autoSearch();
}
}
$("#loc").submit(function(e) {
e.preventDefault();
// when the user clicks the location search button,
// send a request to nominatim for an OpenStreatMap data search
$.ajax({
url: "http://open.mapquestapi.com/nominatim/v1/search",
data: {
format: "json",
q: $("#loc input").val()
},
dataType: "jsonp",
jsonp: "json_callback",
success: function(results) {
if (results && results.length > 0) {
// if we get a result, relaunch the app to the new location with the old search
// this will allow users to tweet their map
window.location.search = "q=" + encodeURIComponent($("#twit input").val()) + "&l=" + encodeURIComponent($("#loc input").val()) + "¢er=" + results[0].lon + "," + results[0].lat + "&zoom=" + map.geomap("option", "zoom");
}
}
});
return false;
});
$("#twit").submit(function(e) {
e.preventDefault();
// when the user clicks the tweet search button,
// send a request to twitter
if (currentXhr) {
// if there's a search pending, cancel it
currentXhr.abort();
currentXhr = null;
}
$("#popup").hide().html("");
// save our search term
searchTerm = $("#twit input").val();
if (searchTerm) {
// if we have a new search term, relaunch the app to the same location with the new search
// this will allow users to tweet their map
window.location.search = "q=" + encodeURIComponent(searchTerm) + "&l=" + encodeURIComponent($("#loc input").val()) + "¢er=" + map.geomap("option", "center").toString() + "&zoom=" + map.geomap("option", "zoom");
}
return false;
});
// jQueryUI for pretty buttons
$("button").button();
function search() {
// called by autoSearch, this function actually searches Twitter for geo-enabled tweets
if (map !== null) {
var center = map.geomap("option", "center"),
//< the center of the map in lon, lat
// the geocode argument to Twitter search,
// it's an array with [ lat, lon, radius in km ]
// geomap's center is lon, lat so we have to switch
// for radius we'll use document width * pixelSize converted to km (from meters)
// Twitter search has a max of 2500km
geocode = [
center[1], center[0], Math.min(2500, map.geomap("option", "pixelSize") * $(document).width() / 2 / 1000) + "km"],
lastSearchTerm = searchTerm;
// actually send the request to Twitter
currentXhr = $.ajax({
url: "http://search.twitter.com/search.json",
data: {
rpp: 100,
q: lastSearchTerm,
geocode: geocode.join(",")
},
dataType: "jsonp",
complete: function() {
currentXhr = null;
},
success: function(tweets) {
if (searchTerm == lastSearchTerm && tweets.results) {
// if we have results, search each of them for the geo or location property
$.each(tweets.results, function() {
appendTweet(this);
});
$("#appendedCount").text(appendedCount + " tweets mapped!");
}
}
});
}
}
function appendTweet(tweet) {
// attempt to append a tweet if we haven't already
if ($.inArray(tweet.id_str, checkedIds) >= 0) {
return;
}
// we don't want to attempt more than once for a given tweet
checkedIds.push(tweet.id_str);
// store some tweet html as a property on the feature
var feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [0, 0]
},
properties: {
tweet: "<b>" + tweet.from_user + "</b>: " + tweet.text
}
};
if (tweet.geo) {
// if we have a geo property, flip the coordinates because Twitter search isn't
// in proper GeoJSON spec order
// Twitter uses [lat, lon] instead of [lon, lat]
feature.geometry.coordinates = [
tweet.geo.coordinates[1], tweet.geo.coordinates[0]];
map.geomap("append", feature);
appendedCount++;
} else if (tweet.location) {
// otherwise, attempt to geocode the location property
$.ajax({
url: "http://open.mapquestapi.com/nominatim/v1/search",
data: {
format: "json",
q: tweet.location
},
dataType: "jsonp",
jsonp: "json_callback",
success: function(results) {
if (results && results.length > 0) {
// if found, grab the location's lon & lat
if (results[0].lon && results[0].lat) {
feature.geometry.coordinates = [
results[0].lon, results[0].lat];
// finally append the tweet
map.geomap("append", feature);
appendedCount++;
$("#appendedCount").text(appendedCount + " tweets mapped!");
}
}
}
});
}
}
function autoSearch() {
searching = true;
if (searchTerm) {
search();
setTimeout(autoSearch, 5000);
}
}
// for fun, we support sending center, zoom and a tweet query in the query string
var queryString = window.location.search.substring(1),
params = queryString.split("&"),
options = {};
$.each(params, function() {
var idx = this.indexOf("=");
if (idx > 0) {
options[this.substring(0, idx)] = this.substring(idx + 1);
}
});
if (options.center) {
if (options.zoom) {
initMap($.parseJSON("[" + options.center + "]"), parseInt(options.zoom));
} else {
initMap($.parseJSON("[" + options.center + "]"));
}
} else {
// if there's no center in the query string, try to use geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(p) {
initMap([p.coords.longitude, p.coords.latitude]);
}, function(error) {
initMap();
});
} else {
// if all else fails, use defaults
initMap();
}
}
var title = "Twheat !";
if (options.q) {
searchTerm = decodeURIComponent(options.q);
$("#twit input").val(searchTerm);
title += " " + searchTerm;
if (map !== null && !searching) {
autoSearch();
}
}
if (options.l) {
var loc = decodeURIComponent(options.l);
$("#loc input").val(loc);
title += " " + loc;
}
$("title").html(title);
$("#tweetButton").append(twitterButtonHtml);
});
$(function () {
var map = null,
checkedIds = [], //< list of tweet ids we've checked
appendedCount = 0, //< number of tweets we successfully appended
searchTerm = "", //< last search term
searching = false,
currentXhr = null, //< an ajax request reference if we need to cancel
twitterButtonHtml = '<a href="https://twitter.com/share" class="twitter-share-button" data-count="vertical" data-via="ryanttb">Tweet</a><script src="//platform.twitter.com/widgets.js">\x3C/script>';
function initMap(center, zoom) {
// create a map using an optional center and zoom
map = $("#map").geomap({
center: center || [-71.0597732, 42.3584308],
zoom: zoom || 10,
// set the shapeStyle to a largish solid but translucent circle
// to give the tweets a heat map effect
shapeStyle: {
strokeOpacity: 0,
fillOpacity: .2,
width: "16px",
height: "16px",
borderRadius: "16px",
color: "#e44"
},
move: function (e, geo) {
// when the user moves, search for appended tweets
// and show a popup
// clear the popup
$("#popup").hide().html("");
if (searchTerm) {
// spatial query, geo has the cursor location as a map point
// this will find appended tweets within 3 pixels
var features = map.geomap("find", geo, 3),
popupHtml = "",
i = 0;
// for each tweet found, add some html to the popup
for (; i < features.length; i++) {
popupHtml += "<p>" + features[i].properties.tweet + "</p>";
}
if (popupHtml) {
// if any tweets found, show the popup
var $popup = $("#popup").append(popupHtml).css({
left: e.pageX,
top: e.pageY
});
var widthOver = $(window).width() - ( $popup.width() + e.pageX ),
heightOver = ($(window).height() - 32) - ( $popup.height() + e.pageY ),
left = e.pageX,
top = e.pageY;
if ( widthOver < 0 ) {
left += widthOver;
}
if ( heightOver < 0 ) {
top += heightOver;
}
$popup.css({
left: left,
top: top
}).show();
}
}
}
});
if ( searchTerm && !searching ) {
autoSearch();
}
}
$("#loc").submit(function (e) {
e.preventDefault();
// when the user clicks the location search button,
// send a request to nominatim for an OpenStreatMap data search
$.ajax({
url: "http://open.mapquestapi.com/nominatim/v1/search",
data: {
format: "json",
q: $("#loc input").val()
},
dataType: "jsonp",
jsonp: "json_callback",
success: function (results) {
if (results && results.length > 0) {
// if we get a result, relaunch the app to the new location with the old search
// this will allow users to tweet their map
window.location.search =
"q=" + encodeURIComponent($("#twit input").val()) +
"&l=" + encodeURIComponent($("#loc input").val()) +
"¢er=" + results[0].lon + "," + results[0].lat +
"&zoom=" + map.geomap("option", "zoom");
}
}
});
return false;
});
$("#twit").submit(function (e) {
e.preventDefault();
// when the user clicks the tweet search button,
// send a request to twitter
if (currentXhr) {
// if there's a search pending, cancel it
currentXhr.abort();
currentXhr = null;
}
$("#popup").hide().html("");
// save our search term
searchTerm = $("#twit input").val();
if ( searchTerm ) {
// if we have a new search term, relaunch the app to the same location with the new search
// this will allow users to tweet their map
window.location.search =
"q=" + encodeURIComponent(searchTerm) +
"&l=" + encodeURIComponent($("#loc input").val()) +
"¢er=" + map.geomap("option", "center").toString() +
"&zoom=" + map.geomap("option", "zoom");
}
return false;
});
// jQueryUI for pretty buttons
$( "button" ).button();
function search() {
// called by autoSearch, this function actually searches Twitter for geo-enabled tweets
if ( map !== null ) {
var center = map.geomap("option", "center"), //< the center of the map in lon, lat
// the geocode argument to Twitter search,
// it's an array with [ lat, lon, radius in km ]
// geomap's center is lon, lat so we have to switch
// for radius we'll use document width * pixelSize converted to km (from meters)
// Twitter search has a max of 2500km
geocode = [
center[1],
center[0],
Math.min(2500, map.geomap("option", "pixelSize") * $(document).width() / 2 / 1000) + "km"
],
lastSearchTerm = searchTerm;
// actually send the request to Twitter
currentXhr = $.ajax({
url: "http://search.twitter.com/search.json",
data: {
rpp: 100,
q: lastSearchTerm,
geocode: geocode.join(",")
},
dataType: "jsonp",
complete: function () {
currentXhr = null;
},
success: function (tweets) {
if (searchTerm == lastSearchTerm && tweets.results) {
// if we have results, search each of them for the geo or location property
$.each(tweets.results, function () {
appendTweet( this );
});
$("#appendedCount").text(appendedCount + " tweets mapped!");
}
}
});
}
}
function appendTweet( tweet ) {
// attempt to append a tweet if we haven't already
if ( $.inArray( tweet.id_str, checkedIds ) >= 0 ) {
return;
}
// we don't want to attempt more than once for a given tweet
checkedIds.push( tweet.id_str );
// store some tweet html as a property on the feature
var feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [ 0, 0 ]
},
properties: {
tweet: "<b>" + tweet.from_user + "</b>: " + tweet.text
}
};
if (tweet.geo) {
// if we have a geo property, flip the coordinates because Twitter search isn't
// in proper GeoJSON spec order
// Twitter uses [lat, lon] instead of [lon, lat]
feature.geometry.coordinates = [
tweet.geo.coordinates[1],
tweet.geo.coordinates[0]
];
map.geomap("append", feature);
appendedCount++;
} else if ( tweet.location ) {
// otherwise, attempt to geocode the location property
$.ajax({
url: "http://open.mapquestapi.com/nominatim/v1/search",
data: {
format: "json",
q: tweet.location
},
dataType: "jsonp",
jsonp: "json_callback",
success: function (results) {
if (results && results.length > 0) {
// if found, grab the location's lon & lat
if (results[0].lon && results[0].lat) {
feature.geometry.coordinates = [
results[0].lon,
results[0].lat
];
// finally append the tweet
map.geomap( "append", feature );
appendedCount++;
$("#appendedCount").text(appendedCount + " tweets mapped!");
}
}
}
});
}
}
function autoSearch() {
searching = true;
if ( searchTerm ) {
search();
setTimeout(autoSearch, 5000);
}
}
// for fun, we support sending center, zoom and a tweet query in the query string
var queryString = window.location.search.substring(1),
params = queryString.split("&"),
options = {};
$.each(params, function() {
var idx = this.indexOf("=");
if (idx > 0) {
options[this.substring(0, idx)] = this.substring(idx + 1);
}
});
if (options.center) {
if (options.zoom) {
initMap($.parseJSON("[" + options.center + "]"), parseInt(options.zoom));
} else {
initMap($.parseJSON("[" + options.center + "]"));
}
} else {
// if there's no center in the query string, try to use geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (p) {
initMap([p.coords.longitude, p.coords.latitude]);
}, function (error) {
initMap();
});
} else {
// if all else fails, use defaults
initMap();
}
}
var title = "Twheat !";
if (options.q) {
searchTerm = decodeURIComponent(options.q);
$("#twit input").val(searchTerm);
title += " " + searchTerm;
if ( map !== null && !searching ) {
autoSearch();
}
}
if (options.l) {
var loc = decodeURIComponent(options.l);
$("#loc input").val(loc);
title += " " + loc;
}
$("title").html(title);
$("#tweetButton").append(twitterButtonHtml);
});