-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex_public.html
300 lines (207 loc) · 13.3 KB
/
index_public.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<meta name="author" content="Zachary Forest Johnson" />
<title>MLB hit locations on a Google Map</title>
<!-- YUI -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.7.0/build/paginator/assets/skins/sam/paginator.css&2.7.0/build/datatable/assets/skins/sam/datatable.css">
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo-dom-event/yahoo-dom-event.js&2.7.0/build/datasource/datasource-min.js&2.7.0/build/element/element-min.js&2.7.0/build/paginator/paginator-min.js&2.7.0/build/datatable/datatable-min.js"></script>
<!-- Mapstraction -->
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAJOq-F1-5CeJCDUF1QxoJLBSc9HEPH6PQyLG9Zs3AxnXJSuzAXBQG1S5P2Kf6KLQsAoaHLODIXSxRDA" type="text/javascript"></script>
<script type="text/javascript" src="http://www.mapstraction.com/mapstraction-js/mapstraction.js"></script>
<!-- jQuery -->
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!-- jQuery URL parser -->
<script type="text/javascript" src="jquery.url.js"></script>
<!-- css -->
<link rel="stylesheet" type="text/css" href="js-hit-locations-map.css">
</head>
<body>
<div id="wrap">
<h1 id="game">Loading game info...</h1>
<h2 id="venue">Loading stadium info...</h2>
<div id="left">
<!-- HTML Map element - the size must be specified here, or in the CSS -->
<div id="mapstraction"></div>
<h3 id="hitsLoading">Loading hits...</h3>
<p id="legend">
<img class="legendChip_small" src="images/blueDot.png" width="6" height="6" /> = hit, <img class="legendChip_small" src="images/pinkDot.png" width="6" height="6" /> = out, <img class="legendChip_big" src="images/blueDot.png" width="15" height="15" /> = home run, <img class="legendChip_big" src="images/pinkDot.png" width="15" height="15" /> = double play ball
</p>
</div>
<div id="right" class="yui-skin-sam">
<h3 id="ballsInPlay"></h3>
<div id="hitsTable"></div>
</div>
<p>The above mashup loads hit location data from <a href="http://gd2.mlb.com/components/game/mlb/">MLB Gameday</a> data via <a href="http://developer.yahoo.com/yql/">YQL</a> and <a href="http://jquery.com/">jQuery</a>. Data are transformed from an arbitrary pixel coordinate system to latitude-longitude points using methods I describe <a href="">here</a>. Data are presented on <a href="http://maps.google.com/">Google Maps</a> satellite tiles, using <a href="http://mapstraction.com/">Mapstraction</a> as a wrapper. The accompanying <a href="http://developer.yahoo.com/yui/">YUI</a> table shows the same data and allows selection of balls-in-play.</p>
<p>Please excuse the wait: the YQL queries typically take a few secs to gather the game, stadium, and hit data, but in rare cases queries can take upwards of a minute. In rarer cases the whole thing freaks out and you have to hit refresh.</p>
<p>
By default (without a game specified as a url parameter), this page shows the 2009 all star game. To see another game, simply add a <code>gid</code> parameter to the URL. The <code>gid</code> parameter is composed as follows:
<ul>
<li><code>gid_{year}_{month}_{day}_{away_team}mlb_{home_team}mlb_{game_number}</code></li>
</ul>
So, the default <code>gid</code>, the 2009 all star game, is <a href="http://indiemaps.com/js-hit-locations-map/index.html?gid=gid_2009_07_14_aasmlb_nasmlb_1"><code>gid_2009_07_14_aasmlb_nasmlb_1</code></a>. A few other example games:
<ul>
<li><a href="http://indiemaps.com/js-hit-locations-map/index.html?gid=gid_2009_07_10_sdnmlb_sfnmlb_1"><code>gid_2009_07_10_sdnmlb_sfnmlb_1</code></a>: Padres at Giants, July 10, 2009 (2009's only no-hitter)</li>
<li><a href="http://indiemaps.com/js-hit-locations-map/index.html?gid=gid_2009_05_22_phimlb_nyamlb_1"><code>gid_2009_05_22_phimlb_nyamlb_1</code></a>: Phillies at Yankees, May 22, 2009 (includes 2009's <a href="http://www.hittrackeronline.com/">longest homer</a>, 477 ft. by Raul Ibanez)</li>
<li><a href="http://indiemaps.com/js-hit-locations-map/index.html?gid=gid_2009_05_03_oakmlb_seamlb_1"><code>gid_2009_05_03_oakmlb_seamlb_1</code></a>: Athletics at Mariners, May 3, 2009 (the longest game this season)</li>
</ul>
Created by Zachary Forest Johnson of <a href="http://indiemaps.com/blog">indiemaps.com</a>. Just <em>view source</em> to see what's going on. Code is <a href="http://www.opensource.org/licenses/bsd-license.php">BSD</a> licensed and available <a href="http://github.com/indiemaps/js-hit-locations-map/tree/master">on github</a>.
</p>
</div> <!-- wrap -->
<script type="text/javascript">
var stadium;
var game;
var hits;
var hitMarkers = new Array();
var latConv;
var lngConv;
var mapstraction;
var myColumnDefs = [
{key:"inning", label:"Inning", sortable:true, width:50 },
{key:"event", label:"Event", sortable:true, width:50 },
{key:"des", label:"Description", width:350}
];
var myConfigs = {
selectionMode:"single",
height:"488px"
};
$( document ).ready( function() {
$( 'p#legend' ).hide();
var gid = jQuery.url.param("gid");
if ( ! gid ) {
gid = "gid_2009_07_14_aasmlb_nasmlb_1";
}
mapstraction = new Mapstraction('mapstraction','google');
mapstraction.setMapType( Mapstraction.HYBRID );
getGame( gid );
} );
function getGame( gid ) {
var year = gid.substring( 4, 8 );
var month = gid.substring( 9, 11 );
var day = gid.substring( 12, 14 );
var gameQueryURL = "http://query.yahooapis.com/v1/public/yql?q=" +
"select%20*%20from%20games%20where%20year%3D%22" +
year +
"%22%20and%20month%3D%22" +
month +
"%22%20and%20day%3D%22" +
day +
"%22%20and%20gid%3D%22" +
gid +
"%22&format=json&env=http%3A%2F%2Fgithub.com%2Findiemaps%2Fjs-hit-locations-map%2Fraw%2Fmaster%2Fyql%2Fmlb.gd2.env&callback=?";
$.getJSON( gameQueryURL,
function( gameData ) {
game = gameData.query.results.game;
// add teams to game h1
$('#game').html( game.teams.away.name_brief + " at " + game.teams.home.name_brief + " <span id='date'>" + game.date + "<\/span>" );
getStadium( game.stadium_id, gid );
} );
}
function getStadium( sid, gid ) {
var stadiumQueryURL = "http://query.yahooapis.com/v1/public/yql?q=" +
"select%20*%20from%20stadiums%20where%20id%3D%22" +
game.stadium_id +
"%22&format=json&env=http%3A%2F%2Fgithub.com%2Findiemaps%2Fjs-hit-locations-map%2Fraw%2Fmaster%2Fyql%2Fmlb.gd2.env&callback=?";
$.getJSON( stadiumQueryURL,
function( stadiumData ) {
stadium = stadiumData.query.results.stadium;
/*
stadium.geo.home_plate.latitude = 38.909647;
stadium.geo.home_plate.longitude = -77.043439;
*/
$('#venue').text( stadium.name );
var homePlate_latLong = new LatLonPoint( parseFloat( stadium.geo.home_plate.latitude ), parseFloat( stadium.geo.home_plate.longitude ) );
// m per degree
latConv = homePlate_latLong.distance( new LatLonPoint( homePlate_latLong.lat + .001, homePlate_latLong.lng ) ) * 1000000;
lngConv = homePlate_latLong.distance( new LatLonPoint( homePlate_latLong.lat, homePlate_latLong.lng + .001 ) ) * 1000000;
var fieldCenter_feet = { x : 0, y : 250 };
var fieldCenter_feet_rotated = rotatePoint( fieldCenter_feet.x, fieldCenter_feet.y, stadium.geo.orientation.degrees );
var stadiumCenter = new LatLonPoint( homePlate_latLong.lat + feetToMeters( fieldCenter_feet_rotated.y ) / latConv,
homePlate_latLong.lng + feetToMeters( fieldCenter_feet_rotated.x ) / lngConv );
// display the map centered on a latitude and longitude (Google zoom levels)
mapstraction.setCenterAndZoom( stadiumCenter, 18 );
placeBases();
getHits( gid );
} );
}
function getHits( gid ) {
// select * from atbats where gid="gid_2009_07_11_lanmlb_milmlb_1" and hit_x<>"NaN"
// http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20atbats%20where%20gid%3D%22gid_2009_07_11_lanmlb_milmlb_1%22%20and%20hit_x%3C%3E%22NaN%22&format=xml&env=http%3A%2F%2Fgithub.com%2Findiemaps%2Fjs-hit-locations-map%2Fraw%2Fmaster%2Fyql%2Fmlb.gd2.env
var hitsQueryURL = "http://query.yahooapis.com/v1/public/yql?q=" +
"select%20*%20from%20atbats%20where%20gid%3D%22" +
gid +
"%22%20and%20hit_x%3C%3E%22NaN%22&format=json&env=http%3A%2F%2Fgithub.com%2Findiemaps%2Fjs-hit-locations-map%2Fraw%2Fmaster%2Fyql%2Fmlb.gd2.env&callback=?";
$.getJSON( hitsQueryURL,
function( hitsData ) {
hits = hitsData.query.results.atbat;
$.each( hits, function( index, item ) { addHitToMap( item ); } );
$('#hitsLoading').text( "" );
$('#ballsInPlay').text( "Balls in play" );
$( 'p#legend' ).show();
mapstraction.addSmallControls();
var myDataSource = new YAHOO.util.LocalDataSource( hits );
var myDataTable = new YAHOO.widget.ScrollingDataTable( "hitsTable",myColumnDefs,myDataSource,myConfigs );
myDataTable.subscribe( "rowMouseoverEvent", myDataTable.onEventHighlightRow );
myDataTable.subscribe("rowMouseoutEvent", myDataTable.onEventUnhighlightRow);
myDataTable.subscribe( "rowClickEvent",
function( oArgs ) {
myDataTable.onEventSelectRow( oArgs.event );
var selID = myDataTable.getSelectedRows()[0].substring( 7, 9999 );
hitMarkers[ parseInt( selID ) ].openBubble();
} );
}
);
}
function addHitToMap( hit ) {
var hitLocation_feet = { x : ( parseFloat( hit.hit_x ) - parseFloat( stadium.gameday.year2009.home_plate.x ) ) * parseFloat( stadium.gameday.year2009.pixels_per_foot ),
y : ( -parseFloat( hit.hit_y ) + parseFloat( stadium.gameday.year2009.home_plate.y ) ) * parseFloat( stadium.gameday.year2009.pixels_per_foot ) };
var hitLocation_feet_rotated = rotatePoint( hitLocation_feet.x, hitLocation_feet.y, parseFloat( stadium.geo.orientation.degrees ) );
var hitLocation_latLong = new LatLonPoint( parseFloat( stadium.geo.home_plate.latitude ) + feetToMeters( hitLocation_feet_rotated.y ) / latConv,
parseFloat( stadium.geo.home_plate.longitude ) + feetToMeters( hitLocation_feet_rotated.x ) / lngConv );
hit.latitude = hitLocation_latLong.lat;
hit.longitude = hitLocation_latLong.lng;
var hitMarker = new Marker( hitLocation_latLong );
var size = ( hit.event=="Home Run" || hit.event=="Grounded Into DP" ) ? 15 : 6;
var icon = hit.hit_type=="O" ? "images/pinkDot.png" : "images/blueDot.png";
hitMarker.setIcon( icon, [ size, size ] );
hitMarker.setShadowIcon( "images/blank.png", [ 10, 10 ] );
hitMarker.setLabel( hit.event );
hitMarker.setInfoBubble( hit.des );
mapstraction.addMarker( hitMarker );
hitMarkers.push( hitMarker );
}
function placeBases() {
var homePlateMarker = new Marker( new LatLonPoint( parseFloat( stadium.geo.home_plate.latitude ), parseFloat( stadium.geo.home_plate.longitude ) ) );
homePlateMarker.setIcon( "images/base.png", [ 7, 7 ] );
homePlateMarker.setShadowIcon( "images/blank.png", [ 10, 10 ] );
mapstraction.addMarker( homePlateMarker );
var bases_meters_rotated = new Array();
// second base
var secondBase_meters = { x : 0, y : feetToMeters( 127.28125 ) };
bases_meters_rotated.push( rotatePoint( secondBase_meters.x, secondBase_meters.y, parseFloat( stadium.geo.orientation.degrees ) ) );
// first & third base
var firstBase_meters = { x : 0, y : 27.4 };
bases_meters_rotated.push( rotatePoint( firstBase_meters.x, firstBase_meters.y, -45 + parseFloat( stadium.geo.orientation.degrees ) ) );
bases_meters_rotated.push( rotatePoint( firstBase_meters.x, firstBase_meters.y, 45 + parseFloat( stadium.geo.orientation.degrees ) ) );
for ( var i = 0; i < bases_meters_rotated.length; i++ ) {
var base = bases_meters_rotated[ i ];
var baseLocation = new LatLonPoint( parseFloat( stadium.geo.home_plate.latitude ) + base.y / latConv,
parseFloat( stadium.geo.home_plate.longitude ) + base.x / lngConv );
var marker = new Marker( baseLocation );
marker.setIcon( "images/base.png", [ 7, 7 ] );
marker.setShadowIcon( "images/blank.png", [ 10, 10 ] );
mapstraction.addMarker( marker );
}
}
function rotatePoint( x, y, rotation_degrees )
{
var rotation_radians = rotation_degrees / 180 * Math.PI;
return { x : x * Math.cos( rotation_radians ) - y * Math.sin( rotation_radians ),
y : x * Math.sin( rotation_radians ) + y * Math.cos( rotation_radians ) };
}
function feetToMeters( feet ) { return feet / 3.2808399; }
</script>
</body>
</html>