Passed
Push — master ( 986636...4b26a2 )
by Markus
02:21
created

pokemon.maps.js ➔ updateLive   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 20
rs 9.4285

1 Function

Rating   Name   Duplication   Size   Complexity  
A pokemon.maps.js ➔ ... ➔ $.done 0 6 2
1
/** global: google */
2
/** global: pokemon_id */
3
/** global: navigator */
4
var map, heatmap;
5
var pokemonMarkers = [];
6
var updateLiveTimeout;
7
8
var ivMin = 80;
9
var ivMax = 100;
10
11
function initMap() {
12
	$.getJSON('core/json/variables.json', function(variables) {
13
		var latitude = Number(variables['system']['map_center_lat']);
14
		var longitude = Number(variables['system']['map_center_long']);
15
		var zoom_level = Number(variables['system']['zoom_level']);
16
		var pokeimg_suffix = variables['system']['pokeimg_suffix'];
17
18
		map = new google.maps.Map(document.getElementById('map'), {
19
			center: {
20
				lat: latitude,
21
				lng: longitude
22
			},
23
			zoom: zoom_level,
24
			zoomControl: true,
25
			scaleControl: false,
26
			scrollwheel: true,
27
			disableDoubleClickZoom: false,
28
			streetViewControl: false,
29
			mapTypeControlOptions: {
30
				mapTypeIds: [
31
					google.maps.MapTypeId.ROADMAP,
32
					'pogo_style',
33
					'dark_style',
34
				]
35
			}
36
		});
37
38
		$.getJSON('core/json/pogostyle.json', function(data) {
39
			var styledMap_pogo = new google.maps.StyledMapType(data, { name: 'PoGo' });
40
			map.mapTypes.set('pogo_style', styledMap_pogo);
41
		});
42
		$.getJSON('core/json/darkstyle.json', function(data) {
43
			var styledMap_dark = new google.maps.StyledMapType(data, { name: 'Dark' });
44
			map.mapTypes.set('dark_style', styledMap_dark);
45
		});
46
		$.getJSON('core/json/defaultstyle.json', function(data) {
47
			map.set('styles', data);
48
		});
49
50
		$.ajax({
51
			'type': 'GET',
52
			'global': false,
53
			'dataType': 'json',
54
			'url': 'core/process/aru.php',
55
			'data': {
56
				'type': 'maps_localization_coordinates'
57
			}
58
		}).done(function(coordinates) {
59
			if (navigator.geolocation) {
60
				navigator.geolocation.getCurrentPosition(function(position) {
61
					var pos = {
62
						lat: position.coords.latitude,
63
						lng: position.coords.longitude
64
					};
65
66
					if (position.coords.latitude <= coordinates.max_latitude && position.coords.latitude >= coordinates.min_latitude) {
67
						if (position.coords.longitude <= coordinates.max_longitude && position.coords.longitude >= coordinates.min_longitude) {
68
							map.setCenter(pos);
69
						}
70
					}
71
				});
72
			}
73
		});
74
75
		initHeatmap();
76
		initSelector(pokeimg_suffix);
77
	});
78
}
79
80
function initSelector(pokeimg_suffix) {
81
	$('#heatmapSelector').click(function() {
82
		hideLive();
83
		showHeatmap();
84
		$('#heatmapSelector').addClass('active');
85
		$('#liveSelector').removeClass('active');
86
	});
87
	$('#liveSelector').click(function() {
88
		hideHeatmap();
89
		map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
90
		initLive(pokeimg_suffix);
91
		$('#liveSelector').addClass('active');
92
		$('#heatmapSelector').removeClass('active');
93
	});
94
}
95
96
function initLive(pokeimg_suffix) {
97
	showLive();
98
	$('#liveFilterSelector').rangeSlider({
99
		bounds: {
100
			min: 0,
101
			max: 100
102
		},
103
		defaultValues: {
104
			min: ivMin,
105
			max: ivMax
106
		},
107
		formatter: function(val) {
108
			return 'IV: ' + Math.round(val) + '%';
109
		}
110
	});
111
112
	$('#liveFilterSelector').bind('valuesChanged', function(e, data) {
113
		clearTimeout(updateLiveTimeout);
114
		removePokemonMarkerByIv(data.values.min, data.values.max);
115
		ivMin = data.values.min;
116
		ivMax = data.values.max;
117
		updateLive(pokeimg_suffix);
118
	});
119
	updateLive(pokeimg_suffix);
120
}
121
122
function initHeatmap() {
123
	$.ajax({
124
		'type': 'GET',
125
		'global': false,
126
		'dataType': 'json',
127
		'url': 'core/process/aru.php',
128
		'data': {
129
			'type': 'pokemon_slider_init'
130
		}
131
	}).done(function(bounds) {
132
		initHeatmapData(bounds);
133
	});
134
}
135
136
function initHeatmapData(bounds) {
137
	var boundMin = new Date(bounds.min.replace(/-/g, '/'));
138
	var boundMax = new Date(bounds.max.replace(/-/g, '/'));
139
	var selectorMax = boundMax;
140
	var selectorMin = boundMin;
141
142
	// two weeks in millisec
143
	var twoWeeks = 12096e5;
144
	var maxMinus2Weeks = new Date(selectorMax.getTime() - twoWeeks);
145
	if (selectorMin < maxMinus2Weeks) {
146
		selectorMin = maxMinus2Weeks;
147
	}
148
149
	// dict with millisec => migration nr.
150
	var migrations = {};
151
	// start at 4 because 06. Oct 2016 was the 4th migration
152
	var migr_nr = 4;
153
	$('#timeSelector').dateRangeSlider({
154
		bounds: {
155
			min: boundMin,
156
			max: boundMax
157
		},
158
		defaultValues: {
159
			min: selectorMin,
160
			max: selectorMax
161
		},
162
		scales: [{
163
			first: function(value) {
164
				// 06. Oct 2016 (4th migration). 2 week schedule starts with this migration
165
				var migrationStart = new Date('2016-10-06T00:00:00Z');
166
				var now = new Date();
167
				var result = new Date();
168
				for (var migration = migrationStart; migration <= now; migration.setTime(migration.getTime() + twoWeeks)) {
169
					if (migration >= value) {
170
						result = migration;
171
						migrations[result.getTime()] = migr_nr;
172
						break;
173
					}
174
					migr_nr++;
175
				}
176
				return result;
177
			},
178
			next: function(value) {
179
				var next = new Date(new Date(value).setTime(value.getTime() + twoWeeks));
180
				migr_nr++;
181
				migrations[next.getTime()] = migr_nr;
182
				return next;
183
			},
184
			label: function(value) {
185
				if (isMobileDevice() && isTouchDevice()) {
186
					return '#' + migrations[value.getTime()];
187
				}
188
				return 'Migration #' + migrations[value.getTime()];
189
			},
190
		}]
191
	});
192
	createHeatmap();
193
}
194
195
function createHeatmap() {
196
197
	heatmap = new google.maps.visualization.HeatmapLayer({
198
		data: [],
199
		map: map
200
	});
201
202
	var gradient = [
203
		'rgba(0, 255, 255, 0)',
204
		'rgba(0, 255, 255, 1)',
205
		'rgba(0, 191, 255, 1)',
206
		'rgba(0, 127, 255, 1)',
207
		'rgba(0, 63, 255, 1)',
208
		'rgba(0, 0, 255, 1)',
209
		'rgba(0, 0, 223, 1)',
210
		'rgba(0, 0, 191, 1)',
211
		'rgba(0, 0, 159, 1)',
212
		'rgba(0, 0, 127, 1)',
213
		'rgba(63, 0, 91, 1)',
214
		'rgba(127, 0, 63, 1)',
215
		'rgba(191, 0, 31, 1)',
216
		'rgba(255, 0, 0, 1)'
217
	];
218
	heatmap.set('gradient', gradient);
219
	heatmap.setMap(map);
220
	$('#timeSelector').bind('valuesChanged', function() { updateHeatmap() });
221
	$('#timeSelector').dateRangeSlider('min'); // will trigger valuesChanged
222
}
223
224
function updateHeatmap() {
225
	var dateMin = $('#timeSelector').dateRangeSlider('min');
226
	var dateMax = $('#timeSelector').dateRangeSlider('max');
227
	$('#loaderContainer').show();
228
	$.ajax({
229
		'type': 'GET',
230
		'global': false,
231
		'dataType': 'json',
232
		'url': 'core/process/aru.php',
233
		'data': {
234
			'type': 'pokemon_heatmap_points',
235
			'pokemon_id': pokemon_id,
236
			'start': Math.floor(dateMin.getTime() / 1000),
237
			'end': Math.floor(dateMax.getTime() / 1000)
238
		}
239
	}).done(function(points) {
240
		var googlePoints = [];
241
		for (var i = 0; i < points.length; i++) {
242
			googlePoints.push(new google.maps.LatLng(points[i].latitude, points[i].longitude))
243
		}
244
		var newPoints = new google.maps.MVCArray(googlePoints);
245
		heatmap.set('data', newPoints);
246
		$('#loaderContainer').hide();
247
	});
248
}
249
250
function hideHeatmap() {
251
	$('#timeFilterContainer').hide();
252
	heatmap.set('map', null);
253
}
254
255
function showHeatmap() {
256
	$('#timeFilterContainer').show();
257
	heatmap.set('map', map);
258
	hideLive();
259
}
260
261
function hideLive() {
262
	$('#liveFilterContainer').hide();
263
	clearTimeout(updateLiveTimeout);
264
	clearPokemonMarkers();
265
}
266
267
function showLive() {
268
	hideHeatmap();
269
	clearTimeout(updateLiveTimeout);
270
	$('#liveFilterContainer').show();
271
272
}
273
274
function updateLive(pokeimg_suffix) {
275
	$.ajax({
276
		'type': 'POST',
277
		'global': false,
278
		'dataType': 'json',
279
		'url': 'core/process/aru.php',
280
		'data': {
281
			'type': 'pokemon_live',
282
			'pokemon_id': pokemon_id,
283
			'inmap_pokemons': extractEncountersId(),
284
			'ivMin': ivMin,
285
			'ivMax': ivMax
286
		}
287
	}).done(function(pokemons) {
288
		for (var i = 0; i < pokemons.points.length; i++) {
289
			addPokemonMarker(pokemons.points[i], pokeimg_suffix, pokemons.locale)
290
		}
291
		updateLiveTimeout = setTimeout(function() { updateLive(pokeimg_suffix) }, 5000);
292
	});
293
}
294
295
function addPokemonMarker(pokemon, pokeimg_suffix, locale) {
296
	var image = {
297
		url: 'core/pokemons/' + pokemon.pokemon_id + pokeimg_suffix,
298
		scaledSize: new google.maps.Size(32, 32),
299
		origin: new google.maps.Point(0, 0),
300
		anchor: new google.maps.Point(16, 16),
301
		labelOrigin: new google.maps.Point(16, 36)
302
	};
303
	var encounter = false;
304
	var ivPercent = 100;
305
	if (pokemon.individual_attack !== null) {
306
		encounter = true;
307
		ivPercent = ((100 / 45) * (parseInt(pokemon.individual_attack) + parseInt(pokemon.individual_defense) + parseInt(pokemon.individual_stamina))).toFixed(2);
308
	}
309
	var marker = new google.maps.Marker({
310
		position: { lat: parseFloat(pokemon.latitude), lng: parseFloat(pokemon.longitude) },
311
		map: map,
312
		icon: image,
313
		encounterId: pokemon.encounter_id,
314
		ivPercent: ivPercent
315
	});
316
	if (encounter) {
317
		marker.setLabel({
318
			color: getIvColor(ivPercent),
319
			text: ivPercent + '%'
320
		});
321
	}
322
	var contentString = '<div>' +
323
		'<h4> ' + pokemon.name + ' #' + pokemon.pokemon_id + (encounter ? ' IV: ' + ivPercent + '% ' : '') + '</h4>' +
324
		'<div id="bodyContent">' +
325
		'<p class="disappear_time_display text-center">' + pokemon.disappear_time_real + '<span class="disappear_time_display_timeleft"></span></p>';
326
	if (encounter) {
327
		contentString +=
328
			'<p></p>' +
329
			'<div class="progress" style="height: 6px; width: 120px; margin-bottom: 10px; margin-top: 2px; margin-left: auto; margin-right: auto">' +
330
			'<div title="' + locale.ivAttack + ': ' + pokemon.individual_attack + '" class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="' + pokemon.individual_attack + '" aria-valuemin="0" aria-valuemax="45" style="width: ' + (((100 / 15) * pokemon.individual_attack) / 3) + '%">' +
331
			'<span class="sr-only">' + locale.ivAttack + ': ' + pokemon.individual_attack + '</span>' +
332
			'</div>' +
333
			'<div title="' + locale.ivDefense + ': ' + pokemon.individual_defense + '" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="' + pokemon.individual_defense + '" aria-valuemin="0" aria-valuemax="45" style="width: ' + (((100 / 15) * pokemon.individual_defense) / 3) + '%">' +
334
			'<span class="sr-only">' + locale.ivDefense + ': ' + pokemon.individual_defense + '</span>' +
335
			'</div>' +
336
			'<div title="' + locale.ivStamina + ': ' + pokemon.individual_stamina + '" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="' + pokemon.individual_stamina + '" aria-valuemin="0" aria-valuemax="45" style="width: ' + (((100 / 15) * pokemon.individual_stamina) / 3) + '%">' +
337
			'<span class="sr-only">' + locale.ivStamina + ': ' + pokemon.individual_stamina + '</span>' +
338
			'</div>' +
339
			'</div>' +
340
			'<p class="text-center">(' + pokemon.individual_attack + "/" + pokemon.individual_defense + "/" + pokemon.individual_stamina + ')</p>' +
341
			'<p class="text-center">' + pokemon.quick_move + "/" + pokemon.charge_move + '</p>';
342
	}
343
	contentString += '</div>';
344
345
	var infoWindow = new google.maps.InfoWindow({
346
		content: contentString
347
	});
348
	infoWindow.isClickOpen = false;
349
	marker.addListener('click', function() {
350
		infoWindow.isClickOpen = true;
351
		infoWindow.open(map, this);
352
	});
353
	google.maps.event.addListener(infoWindow, 'closeclick', function() {
354
		this.isClickOpen = false;
355
	});
356
	marker.addListener('mouseover', function() {
357
		infoWindow.open(map, this);
358
	});
359
360
	// assuming you also want to hide the infowindow when user mouses-out
361
	marker.addListener('mouseout', function() {
362
		if (infoWindow.isClickOpen === false) {
363
			infoWindow.close();
364
		}
365
	});
366
	pokemonMarkers.push(marker);
367
	var now = new Date().getTime();
368
	var endTime = new Date(pokemon.disappear_time_real.replace(/-/g, '/')).getTime();
369
370
	setTimeout(function() { removePokemonMarker(pokemon.encounter_id) }, endTime - now);
371
}
372
373
374
function getIvColor(ivPercent) {
375
	var ivColor = 'rgba(0, 0, 0, 0)';
376
	if (ivPercent > 80) {
377
		ivColor = 'rgba(0, 0, 255, 0.70)';
378
	}
379
	if (ivPercent > 90) {
380
		ivColor = 'rgba(246, 178, 107, 0.90)';
381
	}
382
	if (ivPercent > 99) {
383
		ivColor = 'rgba(255, 0, 0, 1)';
384
	}
385
	return ivColor;
386
}
387
388
function clearPokemonMarkers() {
389
	for (var i = 0; i < pokemonMarkers.length; i++) {
390
		pokemonMarkers[i].setMap(null);
391
	}
392
	pokemonMarkers = [];
393
}
394
395
function removePokemonMarker(encounter_id) {
396
	for (var i = 0; i < pokemonMarkers.length; i++) {
397
		if (pokemonMarkers[i].encounterId == encounter_id) {
398
			pokemonMarkers[i].setMap(null);
399
			pokemonMarkers.splice(i, 1);
400
			break;
401
		}
402
	}
403
}
404
405
function removePokemonMarkerByIv(ivMin, ivMax) {
406
	var cleanMarkers = [];
407
	for (var i = 0; i < pokemonMarkers.length; i++) {
408
		if (pokemonMarkers[i].ivPercent < ivMin || pokemonMarkers[i].ivPercent > ivMax) {
409
			pokemonMarkers[i].setMap(null);
410
		} else {
411
			cleanMarkers.push(pokemonMarkers[i]);
412
		}
413
	}
414
	pokemonMarkers = cleanMarkers;
415
}
416
417
function extractEncountersId() {
418
	var inmapEncounter = [];
419
	for (var i = 0; i < pokemonMarkers.length; i++) {
420
		inmapEncounter[i] = pokemonMarkers[i].encounterId;
421
	}
422
	return inmapEncounter;
423
}
424
425
function isTouchDevice() {
426
	// Should cover most browsers
427
	return 'ontouchstart' in window || navigator.maxTouchPoints
428
}
429
430
function isMobileDevice() {
431
	// Basic mobile OS (not browser) detection
432
	return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
433
}