westdc-zf1/htdocs/js/timemap.2.0.1/examples/google_spreadsheet_heatmap....

296 lines
11 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Spreadsheet, Arbitrary Columns Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAASI0kCI-azC8RgbOZzWc3VRRarOQe_TKf_51Omf6UUSOFm7EABRRhO0PO4nBAO9FCmVDuowVwROLo3w"
type="text/javascript"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="../lib/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="../lib/mxn/mxn.js?(googlev3)"></script>
<script src="../lib/timeline-2.3.0.js" type="text/javascript"></script>
<script src="../src/timemap.js" type="text/javascript"></script>
<script src="../src/param.js" type="text/javascript"></script>
<script src="../src/loaders/json.js" type="text/javascript"></script>
<script src="../src/loaders/google_spreadsheet.js" type="text/javascript"></script>
<script src="../src/ext/circle_icons.js" type="text/javascript"></script>
<script type="text/javascript">
// We're going to define a new loader class extending the spreadsheet loader, which
// will do both the transformation and the consolidation by title in the preload
TimeMap.loaders.custom_gss = function(options) {
var loader = new TimeMap.loaders.gss(options),
extraColumns = options.extraColumns || [];
// We want the transform function, but not as such;
// save it under a different name and clear the function
loader.oldTransform = loader.transform;
loader.transform = function(data) { return data; };
// Do both transform and consolidation in the preload function
loader.preload = function(data) {
// basic preload: get rows
var rows = data.feed.entry,
counties = {}, items = [],
parser = TimeMap.dateParsers.hybrid,
item, i;
for (i=0; i < rows.length; i++) {
// call the original loader transform to get the formatted object
item = loader.oldTransform(rows[i]);
// consolidate by title (county)
if (!(item.title in counties)) {
// make an EventIndex for the data
item.options.dates = new SimileAjax.EventIndex(null);
// add to county map
counties[item.title] = item;
}
// save the data as a pseudo-event to the EventIndex
// (have to wrap in an anonymous function to fix scope)
(function(start) {
var d = parser(start),
datapoint = {
// these functions are to make it behave like an event
getStart: function() {
return d;
},
getEnd: function() {
return d;
},
getID: function() {
return start;
}
};
// add the data we care about; assuming it's extraColumns
for (x=0; x < extraColumns.length; x++) {
paramName = extraColumns[x];
datapoint[paramName] = item.options[paramName];
}
counties[item.title].options.dates.add(datapoint);
})(item.start);
}
// turn the consolidated items into an array again
for (i in counties) {
if (counties.hasOwnProperty(i)) {
item = counties[i];
// while we're at it, let's turn this into a duration event
item.start = item.options.dates.getEarliestDate();
item.end = item.options.dates.getLatestDate();
items.push(item);
}
}
return items;
}
// return the customized loader
return loader;
};
/**
* Get the current data, by date, for a particular item.
*
* @param {Date} d Current date
* @return {Object} Most recent data object for the current date
*/
TimeMapItem.prototype.getData = function(d) {
// get center date if none is supplied
d = d || this.dataset.timemap.timeline.getBand(0).getMaxVisibleDate(),
dates = this.opts.dates;
// look for the most recent data point in the past
var iterator = dates.getReverseIterator(this.getStart(), d);
if (!iterator.hasNext()) {
// event only exists in the future
return null;
}
return iterator.next();
};
/**
* Make an array of scaled circle icons and add them to a theme
*
* @param {TimeMapTheme} theme Theme to modify
*/
TimeMapTheme.addScaledIcons = function(theme) {
var imgPath = theme.eventIconPath,
icons = [], i,
sizes = [4,5,7,10,13,16,20,23,26,28];
// make icons
for (i=0; i<sizes.length; i++) {
icons.push(
TimeMapTheme.getCircleUrl(sizes[i], theme.color, 'bb')
);
}
// add to theme
theme.scaledIcons = icons;
};
/**
* Initialize the filter chain for the heatmap.
*/
TimeMap.prototype.initHeatmap = function() {
// this function needs to be set in the timemap options;
// it should take a data object and return a value 0-9
var getScaleFromData = tm.opts.getScaleFromData;
if (!getScaleFromData) return;
// add heatmap filter chain
tm.addFilterChain("heatmap",
// true condition: change marker icon
function(item) {
var data = item.getData(),
theme = item.opts.theme;
if (data) {
item.showPlacemark();
var scale = getScaleFromData(data),
newIcon = theme.scaledIcons[scale];
// note that this is specific to Google v3
item.getNativePlacemark().setIcon(newIcon);
} else {
item.hidePlacemark();
}
},
// false condition: do nothing
function(item) { }
);
// filter: change icon if visible
tm.addFilter("heatmap", function(item) {
return item.placemarkVisible;
});
// add listener for filter chain
tm.timeline.getBand(0).addOnScrollListener(function() {
tm.filter("heatmap");
});
};
var tm;
$(function() {
// make the theme
var theme = TimeMapTheme.createCircleTheme();
TimeMapTheme.addScaledIcons(theme);
theme.icon = theme.scaledIcons[0];
tm = TimeMap.init({
mapId: "map", // Id of map div element (required)
timelineId: "timeline", // Id of timeline div element (required)
options: {
theme: theme,
getScaleFromData: function(data) {
return (data["log1.6"] > 9) ? 9 : parseInt(data["log1.6"]);
},
mapFilter: "hideFuture",
// there isn't going to be a good way to show 139 duration events on the timeline
noEventLoad: true
},
datasets: [
{
title: "Events",
id: "events",
type: "custom_gss",
options: {
// note that your spreadsheet must be published for this to work
key: "tnobdBZ6zvWAWVZEW-uBW1Q",
// map spreadsheet column names to expected ids
paramMap: {
start: "year"
},
// load extra data from non-standard spreadsheet columns
extraColumns: [
"count",
"cumulative",
"log1.6"
],
openInfoWindow: function() {
var item = this,
data = item.getData();
item.opts.infoHtml = '<div class="infotitle">' + item.getTitle() + '</div>';
if (data) {
item.opts.infoHtml += '<div class="itemdata">'
+ '<p><em>Year: </em>' + data.getID() + '</p>'
+ '<p><em>Deaths: </em>' + data.count + '</p>'
+ '<p><em>Cumulative: </em>' + data.cumulative + '</p>'
+ '<div>';
}
// use basic window opener
TimeMapItem.openInfoWindowBasic.call(item);
}
}
}
],
// lay out timeline for a thin navigational display
bandInfo: [
{
width: "60%",
intervalUnit: Timeline.DateTime.YEAR,
intervalPixels: 70
},
{
width: "40%",
intervalUnit: Timeline.DateTime.DECADE,
intervalPixels: 160
}
],
// set up filter once the timeline is loaded
dataDisplayedFunction: function(tm) {
tm.initHeatmap();
tm.filter("heatmap");
},
// we aren't loading the items, so we need to set this manually
scrollTo: '1969'
});
});
</script>
<link href="examples.css" type="text/css" rel="stylesheet"/>
<style>
div#timelinecontainer{
width: 100%;
height: 20%;
}
div#timeline{
width: 100%;
height: 100%;
font-size: 12px;
background: #CCCCCC;
}
div#mapcontainer {
width: 100%;
height: 80%;
}
#timemap {
height: 650px;
}
div#map {
width: 100%;
height: 100%;
background: #EEEEEE;
}
div.itemdata {
font-size: 14px;
}
div.itemdata p {
padding: 0;
margin: .5em 0 0 0;
}
</style>
</head>
<body>
<div id="help">
<h1>Temporal Heatmap from a Google Spreadsheet</h1>
In this example, we're loading items from a Google Spreadsheet (<a href="http://spreadsheets.google.com/pub?key=tnobdBZ6zvWAWVZEW-uBW1Q" target=_blank>published here</a>) and sizing the markers on the map according to a data point in the spreadsheet (in this case, cumulative deaths from asbestosis and silicosis in Texas). This is still a bit of a work in progress; unfortunately, getting the performance to be reasonable means that the marker click area is a little wonky.
</div>
<div id="timemap">
<div id="timelinecontainer">
<div id="timeline"></div>
</div>
<div id="mapcontainer">
<div id="map"></div>
</div>
</div>
</body>
</html>