Skip to content

Instantly share code, notes, and snippets.

@clintconklin
Last active December 30, 2015 23:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clintconklin/7904705 to your computer and use it in GitHub Desktop.
Save clintconklin/7904705 to your computer and use it in GitHub Desktop.
jquery map plugin for retrieving json data and plotting the results in an arbitrary container; for more details, see http://blog.clintconklin.com/plotting-google-map-points-in-a-custom-arbitrary-element/
/*
options:
- datasource (requred): where to fetch the json data from
- bounds (required): the bounds option should come in like so:
{
'lat': {
'from': 36.32,
'to': 39.28
},
'lng': {
'from': -75.15,
'to': -83.41
}
}
- typeEvents (optional; default - all): restrict type of event
- numEvents (optional; default - 5): the number of events to show on the map
- markerOffset(optional; defaults to 0) - any additional marker offset; specify like so:
{
'x': -7,
'y': -7
}
*/
(function($) {
var _PI = 3.1415926535898;
var methods = {
'init': function(options) {
return this.each(function() {
var $this = $(this),
data = $this.data('map');
if (!data) { // plugin not initialized; setup
var typeEvents = (typeof options.typeEvents != 'undefined') ? options.typeEvents : 'all';
var numEvents = (typeof options.numEvents != 'undefined') ? options.numEvents : 5;
var markerOffset = (typeof options.markerOffset != 'undefined') ? options.markerOffset : { 'x': 0, 'y': 0};
options.bounds.lng.delta = options.bounds.lng.to - options.bounds.lng.from;
options.bounds.lat.bottomDegree = options.bounds.lat.to * _PI / 180;
var dimensions = {
'width': $this.width(),
'height': $this.height()
};
var marker = {
'class': options.markerClass || 'marker',
'offset': null
};
var tempMarker = $('<span class="' + (options.markerClass || 'marker') + '"></span>');
// get our marker offsets
tempMarker.css({ 'position': 'absolute', 'opacity': 0 });
$this.append(tempMarker);
marker.offset = {
'x': Math.round(tempMarker.width() / 2) + markerOffset.x,
'y': Math.round(tempMarker.height() / 2) + markerOffset.y
};
tempMarker = tempMarker.remove();
tempMarker = null;
var events = [];
$.ajax({
'dataType': 'json',
'dataFilter': function(response, type) {
response = response.trim();
if (response.substr(0, 2) == '//') {
response = response.substr(2, response.length);
}
return response;
},
'url': options.datasource + '&type=' + encodeURIComponent(typeEvents) + '&results_per_page=' + encodeURIComponent(numEvents),
'success': function(response) {
var results = [], keys = response.RECORDS.COLUMNS, values = response.RECORDS.DATA;
// parse the cf json into something a little less unruly
for (var x = 0, length = values.length; x < length; x++) {
var currentValues = values[x];
var parsed = {};
for (var y = 0, valuesLength = currentValues.length; y < valuesLength; y++) {
parsed[keys[y].toLowerCase()] = currentValues[y];
}
results.push(parsed);
}
for (x = 0; x < results.length; x++) {
events.push({
'id': results[x].uid,
'url': results[x].url,
'name': results[x].name,
'date': results[x].date,
'summary': results[x].summary,
'desc': results[x].description,
'lat': results[x].lat,
'lng': results[x].lng,
'thumbnail': results[x].thumbnail
});
}
$this.data('map', {
'tgarget': $this,
'bounds': options.bounds,
'events': events,
'dimensions': dimensions,
'marker': marker
});
$this.map('populate');
}
});
}
});
}, // init
'populate': function() {
return this.each(function() {
var $this = $(this),
data = $this.data('map');
var markers = [];
$.each(data.events, function(index, event) {
var coords = $this.map('getXY', { 'lat': event.lat, 'lng': event.lng });
// the id is a temp hack that won't work if there are multiple maps on a page; probably need to add an id to the init options
var marker = $('<a id="marker-' + index + '" class="' + data.marker['class'] + '"></a>');
marker.css({
'position': 'absolute',
'left': (coords.x - data.marker.offset.x) + 'px',
'top': (coords.y - data.marker.offset.y) + 'px'
});
var desc = $(event.desc); // objects are easier to manipulate with script
if (event.thumbnail && event.thumbnail != '') {
desc.prepend($('<div class="popover-img"><img src="' + event.thumbnail + '" /></div>'))
}
if (event.friendly_url) {
desc.append($('<span>&nbsp;</span><a href="' + event.friendly_url + '">Read more.</a>'));
}
desc = desc.html();
marker.popoverextended({
'placement': 'top',
'html': true,
'title': event.name,
'content': desc,
'addClass': 'popover-map'
});
marker.on('show', function() {
$.each(markers, function(x, m) {
if (m.attr('id') != 'marker-' + index) {
m.popoverextended('hide');
}
});
});
marker.appendTo(data.target);
markers.push(marker);
});
});
}, // populate
/*
http://stackoverflow.com/questions/6172355/how-to-convert-lat-long-to-an-xy-coordinate-system-e-g-utm-and-then-map-this
Assuming this map does not cross prime meridian
Assuming pixel 0,0 is upper left, and pixel 600,800 is lower right.
Assuming map is Northern Hemisphere Only (no part of map is southern hemisphere)
Determine the left-most longitude in your 800x600 image (X)
Determine the east-most longitude in your 800x600 image (Y)
Determine Longitude-Diff (Z = Y - X)
Determine north-most latitude in your 800x600 image (A)
Determine south-most latitude in your 800x600 image (B)
Determine Longitude-Diff (C = A - B)
Given a Latitude and Longitude, to determine which pixel they clicked on:
J = Input Longitude
K = Input Latitude
Calculate X-pixel
XPixel = CInt(((Y - J) / CDbl(Z)) * 800)
Calculate Y-pixel
YPixel = CInt(((A - K) / CDbl(C)) * 600)
*/
'getXY': function(coords) {
var $this = $(this),
data = $this.data('map');
var x = data.bounds.lng.to;
var y = data.bounds.lng.from;
var z = y - x;
var a = data.bounds.lat.from;
var b = data.bounds.lat.to;
var c = a - b;
return {
'x': (((y - coords.lng) / z) * data.dimensions.width),
'y': (((a - coords.lat) / c) * data.dimensions.height)
};
},
'destroy': function() {
return this.each(function() {
var $this = $(this),
data = $this.data('map');
$(window).unbind('.map');
data.map.remove();
$this.removeData('map');
});
} // destroy
}; // methods
$.fn.map = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.map');
}
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment