Failed Conditions
Pull Request — master (#250)
by
unknown
04:09 queued 01:37
created

core/js/pokemon.maps.js   D

Complexity

Total Complexity 71
Complexity/F 1.61

Size

Lines of Code 467
Function Count 44

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 0
c 6
b 0
f 0
nc 1
dl 0
loc 467
rs 4.0769
wmc 71
mnd 3
bc 67
fnc 44
bpm 1.5227
cpm 1.6136
noi 1

21 Functions

Rating   Name   Duplication   Size   Complexity  
B pokemon.maps.js ➔ createHeatmap 0 28 1
A pokemon.maps.js ➔ showHeatmap 0 5 1
A pokemon.maps.js ➔ getArea 0 6 1
B pokemon.maps.js ➔ initLive 0 26 1
A pokemon.maps.js ➔ initHeatmapData 0 59 2
A pokemon.maps.js ➔ hideLive 0 5 1
A pokemon.maps.js ➔ initHeatmap 0 18 1
A pokemon.maps.js ➔ hideHeatmap 0 4 1
A pokemon.maps.js ➔ isTouchDevice 0 4 1
A pokemon.maps.js ➔ removePokemonMarkerByIv 0 13 4
A pokemon.maps.js ➔ extractEncountersId 0 8 2
B pokemon.maps.js ➔ addPokemonMarker 0 77 5
B pokemon.maps.js ➔ initMap 0 77 1
A pokemon.maps.js ➔ removePokemonMarker 0 11 3
A pokemon.maps.js ➔ isMobileDevice 0 4 1
A pokemon.maps.js ➔ initSelector 0 17 1
B pokemon.maps.js ➔ updateLive 0 24 1
B pokemon.maps.js ➔ updateHeatmap 0 29 1
A pokemon.maps.js ➔ showLive 0 6 1
A pokemon.maps.js ➔ clearPokemonMarkers 0 6 2
A pokemon.maps.js ➔ getIvColor 0 13 4

How to fix   Complexity   

Complexity

Complex classes like core/js/pokemon.maps.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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