Failed Conditions
Pull Request — master (#275)
by Ramiro
03:09
created

pokemon.maps.js ➔ ... ➔ $.then   B

Complexity

Conditions 3
Paths 15

Size

Total Lines 81

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 15
nop 2
dl 0
loc 81
rs 8.8076
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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