mapping-component-package-jp 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +70 -0
  2. package/dist/index.d.ts +264 -0
  3. package/dist/index.js +54 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +54 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +48 -0
  8. package/public/favicon.ico +0 -0
  9. package/public/index.html +43 -0
  10. package/public/logo192.png +0 -0
  11. package/public/logo512.png +0 -0
  12. package/public/manifest.json +25 -0
  13. package/public/robots.txt +3 -0
  14. package/rollup.config.js +48 -0
  15. package/src/components/FabControl.tsx +63 -0
  16. package/src/components/GoogleSearchBar.tsx +182 -0
  17. package/src/components/Icons.tsx +20 -0
  18. package/src/components/JPMapComponent.tsx +96 -0
  19. package/src/components/SpeedDialTool.tsx +97 -0
  20. package/src/components/index.ts +22 -0
  21. package/src/hooks/useMapManager.ts +48 -0
  22. package/src/interfaces/AgnifyMapComponentProps.ts +18 -0
  23. package/src/interfaces/CustomMapOptions.ts +14 -0
  24. package/src/interfaces/Data/EnterpriseRegion.ts +12 -0
  25. package/src/interfaces/Data/Farm.ts +10 -0
  26. package/src/interfaces/Data/Field.ts +19 -0
  27. package/src/interfaces/Data/LocationData.ts +9 -0
  28. package/src/interfaces/Data/MapLocationFeature.ts +8 -0
  29. package/src/interfaces/Data/NDVI.ts +14 -0
  30. package/src/interfaces/GoogleMapsOptions.ts +39 -0
  31. package/src/interfaces/Message.ts +13 -0
  32. package/src/interfaces/Mode.ts +54 -0
  33. package/src/interfaces/Properties.ts +16 -0
  34. package/src/js/fieldEncapsulation/iql.field.js +8 -0
  35. package/src/js/fieldEncapsulation/iql.fieldupload.js +158 -0
  36. package/src/js/fieldEncapsulation/iql.fieldvalidator.js +574 -0
  37. package/src/js/mapEncapsulation/circle.functions.js +30 -0
  38. package/src/js/mapEncapsulation/field.geolocation.js +19 -0
  39. package/src/js/mapEncapsulation/map.common.js +96 -0
  40. package/src/js/mapEncapsulation/mapOverlayManager.d.ts +64 -0
  41. package/src/js/mapEncapsulation/mapOverlayManager.js +2753 -0
  42. package/src/js/mapEncapsulation/shapes/circle.full.js +789 -0
  43. package/src/js/mapEncapsulation/shapes/circle.sector.js +1099 -0
  44. package/src/js/mapEncapsulation/shapes/circle.segment.js +1109 -0
  45. package/src/js/mapEncapsulation/shapes/polygon.customedit.js +393 -0
  46. package/src/js/mapEncapsulation/shapes/polyline.customedit.js +478 -0
  47. package/src/utils/commonUtils.ts +5 -0
  48. package/src/utils/iconUtils.js +52 -0
  49. package/src/utils/mapUtils.ts +88 -0
  50. package/tsconfig.json +20 -0
@@ -0,0 +1,2753 @@
1
+ import { diffLatLng2Meters, formatBlockLabel, get_FillColorOpacity, get_FillColor } from './map.common';
2
+ import { ClearHTML } from '../../utils/mapUtils';
3
+ import { circleToPolygon } from './circle.functions';
4
+ import { IQLPolygonCustomEdit } from './shapes/polygon.customedit';
5
+ import { IQLFieldGeoLocation } from './field.geolocation';
6
+ import polylabel from 'polylabel';
7
+ import polyline from '@mapbox/polyline';
8
+ import { IQLCircleFull } from './shapes/circle.full';
9
+ import { IQLCircleSector } from './shapes/circle.sector';
10
+ import { IQLCircleSegment } from './shapes/circle.segment';
11
+ import { createSvgIcon } from '../../utils/iconUtils';
12
+ import { FieldValidator } from '../fieldEncapsulation/iql.fieldvalidator';
13
+
14
+
15
+
16
+ export class MapOverlayManager {
17
+ constructor(mapInstance) {
18
+
19
+ // #region Private variables
20
+ var _this = this;
21
+ var map = mapInstance;
22
+ var mapId = null;
23
+ var bounds = null;
24
+
25
+ // listeners
26
+ var zoomChangedListener = null;
27
+ var polygonListeners = [];
28
+ var markerListeners = [];
29
+ var mapListeners = [];
30
+
31
+ // event handlers
32
+ var eventHandlers = {};
33
+
34
+ // global variables
35
+ var locPolygons = [];
36
+ var allPoints = [];
37
+ var polygons = [];
38
+ var polyLabels = [];
39
+ var fpolies = [];
40
+ var controlMarkers = [];
41
+ var pointMarkers = [];
42
+ var rmarker = null;
43
+ var pmarker = null;
44
+ var dirmarkers = [];
45
+ var dpolylines = [];
46
+ var rpolylines = [];
47
+ var fmarkers = [];
48
+
49
+ var currentPolylineCustomEdit = null;
50
+ var currentPolygonCustomEdit = null;
51
+ var currentCircleFull = null;
52
+ var currentCircleSector = null;
53
+ var currentCircleSegment = null;
54
+
55
+ var diffLat, diffLng, wdppx, hdppx, hlat, hlng;
56
+
57
+ // Tooltip
58
+ var tipObj = null;
59
+ var ttOffset = { x: 20, y: 20 };
60
+
61
+ // Add new array for background fields
62
+ var backgroundFields = [];
63
+
64
+ function polygonsToMap_set() {
65
+ polygons.forEach(function (p, index) {
66
+ p.setMap(map);
67
+ });
68
+
69
+ locPolygons.forEach(function (lp, index) {
70
+ lp.setMap(map);
71
+ });
72
+
73
+ if (map.getZoom() >= 13) {
74
+ polyLabels.forEach(function (pl, index) {
75
+ pl.setMap(map);
76
+ });
77
+ } else {
78
+ polyLabels.forEach(function (pl, index) {
79
+ pl.setMap(null);
80
+ });
81
+ }
82
+
83
+ zoomChangedListener = google.maps.event.addListener(map, 'zoom_changed', function () {
84
+
85
+ if (map.getZoom() >= 13) {
86
+ polyLabels.forEach(function (pl, index) {
87
+ pl.setMap(map);
88
+ });
89
+ } else {
90
+ polyLabels.forEach(function (pl, index) {
91
+ pl.setMap(null);
92
+ });
93
+ }
94
+ });
95
+
96
+ mapListeners.push(zoomChangedListener);
97
+ }
98
+
99
+ function AddLabel(location, labelColour = "white") {
100
+ var polyCentroidCenter = get_polygon_centroid(location.Poly);
101
+ var labelLat = polyCentroidCenter.y;
102
+ var labelLon = polyCentroidCenter.x;
103
+ var areaText = `${location.Area} ha`;
104
+ var bl = formatBlockLabel(location.Id, location.LocationName, areaText, 8);
105
+
106
+ var svgText = `<svg viewBox="0 0 200 30" xmlns="http://www.w3.org/2000/svg">
107
+ <text x="0" y="12" fill="${labelColour}" font-family="Arial, sans-serif" font-size="8px">${ClearHTML.clearString(location.LocationName)}</text>
108
+ <line x1="0" y1="15" x2="${Math.max(bl.nameWidth, bl.areaWidth)}" y2="15" style="stroke:${labelColour};stroke-width:0.6"/>
109
+ <text x="0" y="24" fill="${labelColour}" font-family="Arial, sans-serif" font-size="8px">${areaText}</text>
110
+ </svg>`;
111
+
112
+ var polyLabel = new google.maps.Marker({
113
+ map: map,
114
+ position: new google.maps.LatLng(parseFloat(labelLat), parseFloat(labelLon)),
115
+ icon: {
116
+ anchor: new google.maps.Point(1.3 * bl.nameWidth / 2, 21),
117
+ url: `data:image/svg+xml;utf-8, ${svgText}`
118
+ },
119
+ id: `pl_${location.Id}`
120
+ });
121
+ polyLabels.push(polyLabel);
122
+ }
123
+
124
+ function get_polygon_centroid(points) {
125
+ var centroid = polylabel(points, 0.00001);
126
+ return { x: centroid[0], y: centroid[1] };
127
+ }
128
+
129
+ function fields_BindPolyEvents() {
130
+ deleteTooltip();
131
+
132
+ polygons.forEach(function (poly) {
133
+ polygonListeners.push(google.maps.event.addListener(poly, 'mouseover', function (event) {
134
+ deleteTooltip();
135
+ injectTooltip(event, poly.content);
136
+ }));
137
+ polygonListeners.push(google.maps.event.addListener(poly, 'mousemove', moveTooltip));
138
+ polygonListeners.push(google.maps.event.addListener(poly, 'mouseout', deleteTooltip));
139
+ polygonListeners.push(google.maps.event.addListener(poly, 'click', function (event) {
140
+ deleteTooltip();
141
+ eventHandlers["FieldOnClick"](this.id);
142
+ }));
143
+ });
144
+ }
145
+
146
+ function farms_BindMarkerEvents() {
147
+ deleteTooltip();
148
+ fmarkers.forEach(function (marker) {
149
+ var ttc = marker.id.split('|');
150
+ markerListeners.push(marker.content.addEventListener('mouseover', function(event) {
151
+ deleteTooltip();
152
+ injectMarkerTooltip(event, ttc[1]+'<br>Farm '+ttc[2]);
153
+ }));
154
+ markerListeners.push(marker.content.addEventListener('mousemove', moveMarkerTooltip));
155
+ markerListeners.push(marker.content.addEventListener('mouseout', deleteTooltip));
156
+ });
157
+ }
158
+
159
+ function regions_BindPolyEvents() {
160
+ deleteTooltip();
161
+
162
+ fpolies.forEach(function (poly) {
163
+ if (poly instanceof google.maps.Polygon) {
164
+ polygonListeners.push(google.maps.event.addListener(poly, 'mouseover', function (event) {
165
+ deleteTooltip();
166
+ injectTooltip(event, poly.get('content'));
167
+ }));
168
+ polygonListeners.push(google.maps.event.addListener(poly, 'mousemove', moveTooltip));
169
+ polygonListeners.push(google.maps.event.addListener(poly, 'mouseout', deleteTooltip));
170
+ polygonListeners.push(google.maps.event.addListener(poly, 'click', function (event) {
171
+ deleteTooltip();
172
+ }));
173
+ } else {
174
+ console.warn('Invalid polygon object found in fpolies array:', poly);
175
+ }
176
+ });
177
+ }
178
+
179
+ function injectTooltip(event, data) {
180
+ if (!tipObj && event) {
181
+ tipObj = document.createElement("div");
182
+ tipObj.style.cssText = "background: rgba(0, 0, 0, 0.5); color: #ffffff; border-radius: 4px; padding: 5px 10px; text-align: left; font-size: 12px; position: fixed;";
183
+ tipObj.innerHTML = data;
184
+ tipObj.style.top = event.domEvent.clientY + window.scrollY + ttOffset.y + "px";
185
+ tipObj.style.left = event.domEvent.clientX + window.scrollX + ttOffset.x + "px";
186
+ document.body.appendChild(tipObj);
187
+ }
188
+ }
189
+
190
+ function injectMarkerTooltip(event, data) {
191
+ if (!tipObj && event) {
192
+ tipObj = document.createElement("div");
193
+ tipObj.style.cssText = "background: rgba(0, 0, 0, 0.5); color: #ffffff; border-radius: 4px; padding: 5px 10px; text-align: left; font-size: 12px; position: fixed;";
194
+ tipObj.innerHTML = data;
195
+ tipObj.style.top = event.clientY + window.scrollY + ttOffset.y + "px";
196
+ tipObj.style.left = event.clientX + window.scrollX + ttOffset.x + "px";
197
+ document.body.appendChild(tipObj);
198
+ }
199
+ }
200
+
201
+ function moveTooltip(event) {
202
+ if (tipObj && event) {
203
+ tipObj.style.top = event.domEvent.clientY + window.scrollY + ttOffset.y + "px";
204
+ tipObj.style.left = event.domEvent.clientX + window.scrollX + ttOffset.x + "px";
205
+ }
206
+ }
207
+
208
+ function moveMarkerTooltip(event) {
209
+ if (tipObj && event) {
210
+ tipObj.style.top = event.clientY + window.scrollY + ttOffset.y + "px";
211
+ tipObj.style.left = event.clientX + window.scrollX + ttOffset.x + "px";
212
+ }
213
+ }
214
+
215
+ function deleteTooltip() {
216
+ if (tipObj) {
217
+ document.body.removeChild(tipObj);
218
+ tipObj = null;
219
+ }
220
+ }
221
+
222
+ function AdvancedMarker(locations, icon, markerType = 'field') {
223
+ if (map.getMapCapabilities().isAdvancedMarkersAvailable && locations && locations.length > 0) {
224
+ var mapBounds = new google.maps.LatLngBounds();
225
+ locations.forEach(function(v) {
226
+ var fmarker;
227
+ var bounds = new google.maps.LatLngBounds();
228
+
229
+ if (markerType === 'farm') {
230
+ bounds.extend(new google.maps.LatLng(v.minLat, v.minLng));
231
+ bounds.extend(new google.maps.LatLng(v.maxLat, v.maxLng));
232
+ } else {
233
+ v.Poly[0].forEach(function(c) {
234
+ bounds.extend(new google.maps.LatLng(parseFloat(c[1]), parseFloat(c[0])));
235
+ });
236
+ }
237
+
238
+ mapBounds.extend(bounds.getCenter());
239
+
240
+ var svgicon = createSvgIcon({
241
+ iconName: icon.name,
242
+ fillColor: icon.style.color,
243
+ width: icon.style.width,
244
+ height: icon.style.height,
245
+ strokeColor: icon.style.strokeColor,
246
+ strokeWidth: icon.style.strokeWidth
247
+ });
248
+
249
+ fmarker = new google.maps.marker.AdvancedMarkerElement({
250
+ map: map,
251
+ position: bounds.getCenter(),
252
+ content: svgicon
253
+ });
254
+
255
+ //we actually don't need this part when passing data as below
256
+ const markerId = markerType === 'farm'
257
+ ? `${v.farmId}|${v.farmOrganization}|${v.farmName}`
258
+ : `${v.Id}|${v.OrganisationName}|${v.FarmName}`;
259
+
260
+ fmarker.setAttribute("id", markerId);
261
+
262
+ if (markerType === 'farm') {
263
+ markerListeners.push(fmarker.addListener("click", () => {
264
+ deleteTooltip();
265
+ eventHandlers["AdvancedMarkerOnClick"]({
266
+ type: 'SUCCESS',
267
+ message: 'farm marker with id ' + fmarker.id + ' clicked',
268
+ code: 200,
269
+ data: v
270
+ });
271
+ }));
272
+ } else {
273
+ markerListeners.push(fmarker.addListener("click", () => {
274
+ deleteTooltip();
275
+ eventHandlers["AdvancedMarkerOnClick"]({
276
+ type: 'SUCCESS',
277
+ message: 'field marker with id ' + fmarker.id + ' clicked',
278
+ code: 200,
279
+ data: v
280
+ });
281
+ }));
282
+ }
283
+
284
+ fmarkers.push(fmarker);
285
+ });
286
+
287
+ if (markerType === 'farm') {
288
+ map.fitBounds(mapBounds);
289
+ farms_BindMarkerEvents();
290
+ }
291
+ }
292
+ }
293
+
294
+ _this.eventHandlers_set = function (eH) {
295
+ Object.assign(eventHandlers, eH);
296
+ };
297
+
298
+ _this.eventHandlers_get = function () {
299
+ return eventHandlers;
300
+ };
301
+
302
+ //#DRAW/DISPLAY FIELDS
303
+ _this.RenderFields = function (locations, properties) {
304
+ var mbounds = new google.maps.LatLngBounds();
305
+
306
+ locations.forEach(function (location) {
307
+ if (location && location.Poly && location.Poly.length > 0 && location.Id.length > 0) {
308
+ var paths = location.Poly.map(poly => poly.map(v => new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0]))));
309
+ paths[0].forEach(coord => mbounds.extend(coord));
310
+
311
+ let content = `${location.FarmName} - ${location.LocationName}<br>${location.Area} ha${location.IsIrrigated ? ', irrigated' : ''}`;
312
+
313
+ if (location.CropPlanted) {
314
+ content += `<br>${location.CropPlanted}`;
315
+ if (location.CultivarPlanted) {
316
+ content += ` (${location.CultivarPlanted})`;
317
+ }
318
+ if (location.PlantingDate) {
319
+ content += `<br>Planted: ${location.PlantingDate.replace(/-/g, "/")}`;
320
+ }
321
+ }
322
+
323
+ var polygonOptions = {
324
+ paths: paths,
325
+ id: location.Id,
326
+ content: content
327
+ }
328
+
329
+ if (location.MapLocationFeature) {
330
+ polygonOptions = {
331
+ ...polygonOptions,
332
+ content,
333
+ strokeColor: location.MapLocationFeature.StrokeColor,
334
+ strokeOpacity: location.MapLocationFeature.StrokeOpacity,
335
+ strokeWeight: location.MapLocationFeature.StrokeWeight,
336
+ fillColor: location.MapLocationFeature.FillColor,
337
+ fillOpacity: location.MapLocationFeature.FillOpacity,
338
+ zIndex: location.MapLocationFeature.ZIndex
339
+ };
340
+ }
341
+ else
342
+ {
343
+ polygonOptions = {
344
+ ...polygonOptions,
345
+ ...properties.polygonOptions.unselected,
346
+ };
347
+ }
348
+
349
+ var polygon = new google.maps.Polygon(polygonOptions);
350
+ polygons.push(polygon);
351
+ if (properties.labelVisable) AddLabel(location);
352
+ }
353
+ });
354
+
355
+ map.fitBounds(mbounds);
356
+ fields_BindPolyEvents();
357
+
358
+ if(properties.icon){
359
+ AdvancedMarker(locations, properties.icon);
360
+ }
361
+
362
+ polygonsToMap_set();
363
+ };
364
+
365
+ _this.destroy = function () {
366
+ mapId = null;
367
+ mapConfig = null;
368
+ locations = [];
369
+ selectedProvinceFieldId = null;
370
+
371
+ defaultCenterLatitude = null;
372
+ defaultCenterLongitude = null;
373
+
374
+ locPolygons = [];
375
+ polygons = [];
376
+ polyLabels = [];
377
+
378
+ _this.map_clear();
379
+ }
380
+
381
+ _this.map_clear = function () {
382
+ // Clear all event listeners
383
+ polygonListeners_clear();
384
+ markerListeners_clear();
385
+ mapListeners_clear();
386
+
387
+ // Clear all markers and controls
388
+ pointMarkers_clear();
389
+ controlMarkers_clear();
390
+ fmarkers_clear();
391
+ rmarker_clear();
392
+ pmarker_clear();
393
+ dirmarkers_clear();
394
+
395
+ // Clear all shapes and labels
396
+ polyLabels_clear();
397
+ polygons_clear();
398
+ locPolygons_clear();
399
+ fPolies_clear();
400
+
401
+ // Clear all lines and custom edits
402
+ dpolyline_clear();
403
+ polylineCustomEdit_clear();
404
+
405
+ // Clear custom shape editors
406
+ if (currentPolygonCustomEdit) {
407
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
408
+ currentPolygonCustomEdit = null;
409
+ }
410
+ if (currentCircleFull) {
411
+ currentCircleFull.setMap(null);
412
+ currentCircleFull = null;
413
+ }
414
+ if (currentCircleSector) {
415
+ currentCircleSector.setMap(null);
416
+ currentCircleSector = null;
417
+ }
418
+ if (currentCircleSegment) {
419
+ currentCircleSegment.setMap(null);
420
+ currentCircleSegment = null;
421
+ }
422
+
423
+ // Clear all overlays
424
+ if (map.overlayMapTypes) {
425
+ while (map.overlayMapTypes.getLength() > 0) {
426
+ map.overlayMapTypes.pop();
427
+ }
428
+ }
429
+
430
+ // Clear any remaining tooltips
431
+ deleteTooltip();
432
+
433
+ // Clear any background fields
434
+ if (backgroundFields.length > 0) {
435
+ backgroundFields.forEach(field => {
436
+ if (field.setMap) {
437
+ field.setMap(null);
438
+ }
439
+ });
440
+ backgroundFields = [];
441
+ }
442
+
443
+ // Reset all arrays
444
+ locPolygons = [];
445
+ allPoints = [];
446
+ polygons = [];
447
+ polyLabels = [];
448
+ fpolies = [];
449
+ controlMarkers = [];
450
+ pointMarkers = [];
451
+ dirmarkers = [];
452
+ dpolylines = [];
453
+ rpolylines = [];
454
+ fmarkers = [];
455
+
456
+ // Reset bounds
457
+ bounds = null;
458
+ }
459
+
460
+ //#region Clear events
461
+
462
+ function rmarker_clear() {
463
+ if(rmarker != null) {
464
+
465
+ rmarker.setMap(null);
466
+ rmarker = null;
467
+ }
468
+ }
469
+
470
+ function pmarker_clear() {
471
+ if(pmarker != null) {
472
+ pmarker.setMap(null);
473
+ pmarker = null;
474
+ }
475
+ }
476
+
477
+ function dirmarkers_clear() {
478
+ //console.log(dirmarkers);
479
+ dirmarkers.forEach(function (dm) {
480
+ dm.setMap(null);
481
+ dm = null;
482
+ });
483
+ dirmarkers = [];
484
+ }
485
+
486
+ function dpolyline_clear() {
487
+ dpolylines.forEach(function (dp) {
488
+ dp.setMap(null);
489
+ dp = null;
490
+ });
491
+ }
492
+
493
+ function pointMarkers_clear() {
494
+ pointMarkers.forEach(function (pm) {
495
+ pm.setMap(null);
496
+ pm = null;
497
+ });
498
+ pointMarkers = [];
499
+ }
500
+
501
+ function controlMarkers_clear() {
502
+ controlMarkers.forEach(function (cm) {
503
+ cm.setMap(null);
504
+ cm = null;
505
+ });
506
+ controlMarkers = [];
507
+ }
508
+
509
+ function fmarkers_clear() {
510
+ fmarkers.forEach(function (fm) {
511
+ fm.setMap(null);
512
+ fm = null;
513
+ });
514
+ fmarkers = [];
515
+ }
516
+
517
+ function polygonListeners_clear() {
518
+ polygonListeners.forEach(function (polygonListener) {
519
+ google.maps.event.removeListener(polygonListener);
520
+ });
521
+ polygonListeners = [];
522
+ }
523
+
524
+ function markerListeners_clear() {
525
+ markerListeners.forEach(function (markerListener) {
526
+ google.maps.event.removeListener(markerListener);
527
+ });
528
+ markerListeners = [];
529
+ }
530
+
531
+ function mapListeners_clear() {
532
+ mapListeners.forEach(function (mapListener) {
533
+ google.maps.event.removeListener(mapListener);
534
+ });
535
+ mapListeners = [];
536
+ }
537
+
538
+ function polyLabels_clear() {
539
+ polyLabels.forEach(function (pl) {
540
+ pl.setMap(null);
541
+ pl = null;
542
+ });
543
+ polyLabels = [];
544
+ }
545
+
546
+ function polygons_clear() {
547
+ polygons.forEach(function (p) {
548
+ p.setMap(null);
549
+ p = null;
550
+ });
551
+ polygons = [];
552
+ }
553
+
554
+ function locPolygons_clear() {
555
+ if (currentPolygonCustomEdit != null) {
556
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
557
+ }
558
+
559
+ locPolygons.forEach(function (lp) {
560
+ lp.setMap(null);
561
+ lp = null;
562
+ });
563
+ locPolygons = [];
564
+ }
565
+
566
+ function polylineCustomEdit_clear() {
567
+ if (currentPolylineCustomEdit != null) {
568
+ currentPolylineCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolylineCustomEdit);
569
+ }
570
+ rpolylines.forEach(function(rp) {
571
+ rp.setMap(null);
572
+ rp = null;
573
+ });
574
+ }
575
+
576
+ function fPolies_clear() {
577
+ fpolies.forEach(function (p, index) {
578
+ p.setMap(null);
579
+ p = null;
580
+ });
581
+ fpolies = [];
582
+ }
583
+
584
+ // #endregion
585
+
586
+ _this.selectShape = function(shapeId, selectedStyle, unselectedStyle) {
587
+ console.log('Selecting shape:', shapeId);
588
+ console.log('Current locPolygons:', locPolygons);
589
+
590
+ locPolygons.forEach(function(polygon) {
591
+ if (polygon) {
592
+ console.log('Applying unselected style to polygon:', polygon.id);
593
+
594
+ if (currentPolygonCustomEdit != null && polygon.isPolygon) {
595
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
596
+ currentPolygonCustomEdit = null;
597
+ polygon.setMap(map);
598
+ }
599
+ if (currentCircleFull != null && polygon.isCircle) {
600
+ currentCircleFull.set('map', null);
601
+ currentCircleFull = null;
602
+ }
603
+ if (currentCircleSector != null && polygon.isCircleSector) {
604
+ currentCircleSector.set('map', null);
605
+ currentCircleSector = null;
606
+ }
607
+ if (currentCircleSegment != null && polygon.isCircleSegment) {
608
+ currentCircleSegment.set('map', null);
609
+ currentCircleSegment = null;
610
+ }
611
+
612
+ polygon.setOptions({
613
+ ...unselectedStyle,
614
+ editable: false,
615
+ draggable: false
616
+ });
617
+ }
618
+ });
619
+
620
+ if (shapeId) {
621
+ const selectedShape = locPolygons.find(p => p.id == shapeId);
622
+ if (selectedShape) {
623
+ console.log('Applying selected style to shape:', shapeId);
624
+ selectedShape.setOptions(selectedStyle);
625
+ } else {
626
+ console.warn('Shape not found in locPolygons:', shapeId);
627
+ }
628
+ }
629
+ };
630
+
631
+ // Add this helper function to check if a shape is in locPolygons
632
+ _this.isShapeInLocPolygons = function(shapeId) {
633
+ return locPolygons.some(p => p.id == shapeId);
634
+ };
635
+
636
+ _this.panAndZoomToShape = function(shapeId) {
637
+ let shape = locPolygons.find(p => p.id == shapeId) || polygons.find(p => p.id == shapeId);
638
+ console.log("locPolygons - panAndZoomToShape", locPolygons);
639
+
640
+ if (shape && map) {
641
+ const bounds = new google.maps.LatLngBounds();
642
+
643
+ if (shape.getPath) {
644
+ shape.getPath().forEach(latLng => bounds.extend(latLng));
645
+ } else if (shape.getCenter && shape.getRadius) {
646
+ const center = shape.getCenter();
647
+ const radius = shape.getRadius();
648
+ bounds.extend(google.maps.geometry.spherical.computeOffset(center, radius, 0));
649
+ bounds.extend(google.maps.geometry.spherical.computeOffset(center, radius, 180));
650
+ } else if (shape.getBounds) {
651
+ bounds.union(shape.getBounds());
652
+ }
653
+
654
+ const currentZoom = map.getZoom();
655
+
656
+ map.fitBounds(bounds, { padding: 50 });
657
+
658
+ google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
659
+ const newZoom = map.getZoom();
660
+
661
+ if (Math.abs(newZoom - currentZoom) > 3) {
662
+ map.setZoom(Math.min(newZoom, 18));
663
+ }
664
+ });
665
+ } else {
666
+ console.error('Shape not found:', shapeId);
667
+ }
668
+ };
669
+
670
+ _this.Shape_Edit = function (ShapeId) {
671
+ locPolygons.forEach((polygon_selected, index) => {
672
+ if (polygon_selected.id === ShapeId) {
673
+ polygon_selected.setEditable(true);
674
+ if (index > 0) {
675
+ polygon_selected.setDraggable(true);
676
+ }
677
+ }
678
+ });
679
+ }
680
+
681
+ _this.Shape_DrawingDone = function (ShapeId) {
682
+ locPolygons.forEach(function (polygon) {
683
+ if (polygon.id == ShapeId) {
684
+ if (polygon.isPolygon) {
685
+ if(currentPolygonCustomEdit != null) {
686
+ var path = currentPolygonCustomEdit.getPath();
687
+ polygon.setPath(path);
688
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
689
+ currentPolygonCustomEdit = null;
690
+ }
691
+ polygon.setMap(map);
692
+ polygon.setEditable(false);
693
+ polygon.setDraggable(false);
694
+ polygon.setVisible(true);
695
+ } else if (polygon.isCircle) {
696
+ var reducedPath = new IQLCircleFull().reduce(currentCircleFull.getPath(), polygon.isHole);
697
+ polygon.setPath(reducedPath);
698
+ polygon.isPolygon = false;
699
+ polygon.isCircle = true;
700
+ polygon.setEditable(false);
701
+ polygon.setDraggable(false);
702
+ currentCircleFull.setMap(null);
703
+ currentCircleFull = null;
704
+ polygon.setVisible(true);
705
+ } else if (polygon.isCircleSector) {
706
+ var reducedPath = new IQLCircleSector().reduce(currentCircleSector.getPath(), polygon.isHole);
707
+ polygon.setPath(reducedPath);
708
+ polygon.isPolygon = false;
709
+ polygon.isCircleSector = true;
710
+ polygon.setEditable(false);
711
+ polygon.setDraggable(false);
712
+ currentCircleSector.setMap(null);
713
+ currentCircleSector = null;
714
+ polygon.setVisible(true);
715
+ } else if (polygon.isCircleSegment) {
716
+ var reducedPath = new IQLCircleSegment().reduce(currentCircleSegment.getPath(), polygon.isHole);
717
+ polygon.setPath(reducedPath);
718
+ polygon.isPolygon = false;
719
+ polygon.isCircleSegment = true;
720
+ polygon.setEditable(false);
721
+ polygon.setDraggable(false);
722
+ currentCircleSegment.setMap(null);
723
+ currentCircleSegment = null;
724
+ polygon.setVisible(true);
725
+ }
726
+ }
727
+ });
728
+
729
+ }
730
+
731
+ _this.Shape_Delete = function (ShapeId, EventHandlers) {
732
+
733
+ const currentBounds = map.getBounds();
734
+ const currentCenter = map.getCenter();
735
+ const currentZoom = map.getZoom();
736
+
737
+ polygonListeners_clear();
738
+ this.eventHandlers_set(EventHandlers);
739
+
740
+ // Check if we're deleting the main shape (first shape)
741
+ const isMainShape = locPolygons.length > 0 && locPolygons[0].id == ShapeId;
742
+
743
+ if (isMainShape) {
744
+ // Delete all shapes if main shape is being deleted
745
+ _this.Shape_DeleteAll();
746
+ return;
747
+ }
748
+
749
+ // Otherwise, proceed with deleting just the selected shape
750
+ var pIndex = -1;
751
+ locPolygons.forEach(function (p, index) {
752
+ if (p.id == ShapeId) {
753
+ if (currentPolygonCustomEdit != null) {
754
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
755
+ currentPolygonCustomEdit = null;
756
+ }
757
+
758
+ if (currentCircleFull != null) {
759
+ currentCircleFull.set('map', null);
760
+ currentCircleFull = null;
761
+ }
762
+
763
+ if (currentCircleSector != null) {
764
+ currentCircleSector.set('map', null);
765
+ currentCircleSector = null;
766
+ }
767
+ if (currentCircleSegment != null) {
768
+ currentCircleSegment.set('map', null);
769
+ currentCircleSegment = null;
770
+ }
771
+
772
+ p.setMap(null);
773
+ pIndex = index;
774
+ }
775
+ });
776
+
777
+ if (pIndex >= 0) {
778
+ locPolygons.splice(pIndex, 1);
779
+ }
780
+
781
+ if (currentCenter && currentBounds) {
782
+ map.setZoom(currentZoom);
783
+ map.setCenter(currentCenter);
784
+ map.fitBounds(currentBounds);
785
+ }
786
+ };
787
+
788
+ _this.Shape_DeleteAll = function (isMobile) {
789
+ const currentBounds = map.getBounds();
790
+ const currentCenter = map.getCenter();
791
+ const currentZoom = map.getZoom();
792
+ polygonListeners_clear();
793
+
794
+ locPolygons.forEach(function (lp) {
795
+ if (currentPolygonCustomEdit != null) {
796
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().delete(map, currentPolygonCustomEdit);
797
+ //console.log(currentPolygonCustomEdit);
798
+ currentPolygonCustomEdit = null;
799
+ }
800
+ if (currentCircleFull != null) {
801
+ currentCircleFull.set('map', null);
802
+ currentCircleFull = null;
803
+ }
804
+ if (currentCircleSector != null) {
805
+ currentCircleSector.set('map', null);
806
+ currentCircleSector = null;
807
+ }
808
+ if (currentCircleSegment != null) {
809
+ currentCircleSegment.set('map', null);
810
+ currentCircleSegment = null;
811
+ }
812
+ lp.setMap(null);
813
+ lp = null;
814
+ });
815
+ locPolygons = [];
816
+
817
+ if (currentCenter && currentBounds) {
818
+ map.setZoom(currentZoom);
819
+ map.setCenter(currentCenter);
820
+ map.fitBounds(currentBounds);
821
+ }
822
+ }
823
+
824
+ //#POLYGON
825
+
826
+ _this.Shape_PolygonCustomEdit_Add = function (isHole, config, isMobile, mapWidth, mapHeight, vmWidth, offsetX, offsetY) {
827
+
828
+ if (!isHole) {
829
+
830
+ var mapBounds = map.getBounds();
831
+ var mapCenter = map.getCenter();
832
+ var mcLat = mapCenter.lat();
833
+ var mcLng = mapCenter.lng();
834
+
835
+ var path = [];
836
+
837
+ if (mapBounds) {
838
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
839
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
840
+ wdppx = diffLng/mapWidth;
841
+ hdppx = diffLat/mapHeight;
842
+
843
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx + 60*hdppx, mcLng + offsetX*wdppx - 80*wdppx));//nw
844
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx + 60*hdppx, mcLng + offsetX*wdppx + 80*wdppx));//ne
845
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx - 60*hdppx, mcLng + offsetX*wdppx + 80*wdppx));//se
846
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx - 60*hdppx, mcLng + offsetX*wdppx - 80*wdppx));//sw
847
+ }
848
+
849
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
850
+
851
+ var shape = new google.maps.Polygon({
852
+ map: map,
853
+ path: path,
854
+ id: pid.toString(),
855
+ content: "",
856
+ strokeColor: config.strokeColor,
857
+ strokeOpacity: config.strokeOpacity,
858
+ strokeWeight: config.strokeWeight,
859
+ fillColor: config.fillColor,
860
+ fillOpacity: config.fillOpacity,
861
+ zIndex: 10100,
862
+ clickable: true,
863
+ editable: false,
864
+ draggable: false,
865
+ isPolygon: true,
866
+ isCircle: false,
867
+ isCircleSector: false,
868
+ isCircleSegment: false,
869
+ isHole: false,
870
+ latitude: 0,
871
+ longitude: 0,
872
+ poly: 0,
873
+ area: 0,
874
+ perimeter: 0
875
+ });
876
+
877
+ locPolygons.push(shape);
878
+
879
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().edit(map, shape, currentPolygonCustomEdit, isMobile);
880
+
881
+ return pid;
882
+
883
+ } else {
884
+
885
+ var holeId = addPolygonHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile);
886
+
887
+ return holeId;
888
+
889
+ }
890
+ }
891
+
892
+
893
+ _this.Shape_Polygon_Add = function (isHole, config, isMobile, mapWidth, mapHeight, vmWidth, offsetX, offsetY) {
894
+
895
+ if(!isHole) {
896
+
897
+ var mapBounds = map.getBounds();
898
+ var mapCenter = map.getCenter();
899
+ var mcLat = mapCenter.lat();
900
+ var mcLng = mapCenter.lng();
901
+
902
+ var path = [];
903
+ var points = [];
904
+ if (mapBounds) {
905
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
906
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
907
+ wdppx = diffLng/mapWidth;
908
+ hdppx = diffLat/mapHeight;
909
+
910
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx + 60*hdppx, mcLng + offsetX*wdppx - 80*wdppx));//nw
911
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx + 60*hdppx, mcLng + offsetX*wdppx + 80*wdppx));//ne
912
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx - 60*hdppx, mcLng + offsetX*wdppx + 80*wdppx));//se
913
+ path.push(new google.maps.LatLng(mcLat + offsetY*hdppx - 60*hdppx, mcLng + offsetX*wdppx - 80*wdppx));//sw
914
+
915
+ points.push([mcLng + offsetX*wdppx - 80*wdppx, mcLat + offsetY*hdppx + 60*hdppx]);
916
+ points.push([mcLng + offsetX*wdppx + 80*wdppx, mcLat + offsetY*hdppx + 60*hdppx]);
917
+ points.push([mcLng + offsetX*wdppx + 80*wdppx, mcLat + offsetY*hdppx - 60*hdppx]);
918
+ points.push([mcLng + offsetX*wdppx - 80*wdppx, mcLat + offsetY*hdppx - 60*hdppx]);
919
+ points.push([mcLng + offsetX*wdppx - 80*wdppx, mcLat + offsetY*hdppx + 60*hdppx]);
920
+
921
+ allPoints.push(points);
922
+
923
+ }
924
+
925
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
926
+
927
+ var shape = new google.maps.Polygon({
928
+ map: map,
929
+ path: path,
930
+ id: pid.toString(),
931
+ content: "",
932
+ strokeColor: config.strokeColor,
933
+ strokeOpacity: config.strokeOpacity,
934
+ strokeWeight: config.strokeWeight,
935
+ fillColor: config.fillColor,
936
+ fillOpacity: config.fillOpacity,
937
+ zIndex: 10100,
938
+ clickable: true,
939
+ editable: true,
940
+ draggable: true,
941
+ isPolygon: true,
942
+ isCircle: false,
943
+ isCircleSector: false,
944
+ isCircleSegment: false,
945
+ isHole: isHole,
946
+ latitude: 0,
947
+ longitude: 0,
948
+ poly: 0,
949
+ area: 0,
950
+ perimeter: 0
951
+ });
952
+ console.log('shape', shape);
953
+
954
+ locPolygons.push(shape);
955
+ return pid;
956
+
957
+ } else {
958
+
959
+ var holeId = addPolygonHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile);
960
+
961
+ return holeId;
962
+ }
963
+
964
+ }
965
+
966
+ function addPolygonHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile) {
967
+
968
+ var nhid;
969
+
970
+ if(typeof wdppx == 'undefined' || typeof hdppx == 'undefined') {
971
+ var mapBounds = map.getBounds();
972
+
973
+ if (mapBounds) {
974
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
975
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
976
+ wdppx = diffLng/mapWidth;
977
+ hdppx = diffLat/mapHeight;
978
+ }
979
+ }
980
+
981
+ allPoints = [];
982
+ locPolygons.forEach(function(lp) {
983
+ var sPath = lp.getPath();
984
+ var points = [];
985
+ for(var c = 0; c < sPath.length; c++) {
986
+ points.push([sPath.getAt(c).lng(), sPath.getAt(c).lat()]);
987
+ }
988
+ if(sPath.getAt(0).lng() != sPath.getAt(sPath.length-1).lng() || sPath.getAt(0).lat() != sPath.getAt(sPath.length-1).lat()) {
989
+ points.push([sPath.getAt(0).lng(), sPath.getAt(0).lat()]);
990
+ }
991
+ allPoints.push(points);
992
+ });
993
+
994
+ var polyCentroidCenter = get_polygon_centroid(allPoints);
995
+
996
+ hlat = polyCentroidCenter.y;
997
+ hlng = polyCentroidCenter.x;
998
+
999
+ for(var i= 20; i > 0;i--) {
1000
+
1001
+ var hps = [];
1002
+ hps.push([hlng - 2*i*wdppx, hlat + 0.75*2*i*hdppx]);
1003
+ hps.push([hlng + 2*i*wdppx, hlat + 0.75*2*i*hdppx]);
1004
+ hps.push([hlng + 2*i*wdppx, hlat - 0.75*2*i*hdppx]);
1005
+ hps.push([hlng - 2*i*wdppx, hlat - 0.75*2*i*hdppx]);
1006
+ hps.push([hlng - 2*i*wdppx, hlat + 0.75*2*i*hdppx]);
1007
+ allPoints.push(hps);
1008
+
1009
+ var notInsideCount = 0;
1010
+ hps.forEach(function(pt,ptIndex) {
1011
+ if (!google.maps.geometry.poly.containsLocation(new google.maps.LatLng(parseFloat(pt[1]), parseFloat(pt[0])), locPolygons[0])) {
1012
+ notInsideCount++;
1013
+ }
1014
+ });
1015
+
1016
+ if (notInsideCount == 0) {
1017
+
1018
+ if(allPoints.length > 2) {
1019
+ var holeIntersectCount = 0;
1020
+ for (var n = 1; n < allPoints.length - 1; n++) {
1021
+ for (var m = n + 1; m < allPoints.length; m++) {
1022
+ if (calcIntersection(allPoints[n], allPoints[m])) {
1023
+ holeIntersectCount++;
1024
+ }
1025
+ }
1026
+ }
1027
+
1028
+ if(holeIntersectCount == 0) {
1029
+ nhid = drawPolygonHole(i, config, offsetX, offsetY, vmWidth, isMobile);
1030
+ break;
1031
+ } else {
1032
+ allPoints.pop();
1033
+ }
1034
+ } else {
1035
+ nhid = drawPolygonHole(i, config, offsetX, offsetY, vmWidth, isMobile);
1036
+ break;
1037
+ }
1038
+ } else {
1039
+ allPoints.pop();
1040
+ }
1041
+ }
1042
+
1043
+ return nhid;
1044
+
1045
+ }
1046
+
1047
+ function calcIntersection(poly1Points, poly2Points) {
1048
+ const polygon1 = new google.maps.Polygon({
1049
+ paths: poly1Points.map(p => new google.maps.LatLng(p[1], p[0]))
1050
+ });
1051
+ const polygon2 = new google.maps.Polygon({
1052
+ paths: poly2Points.map(p => new google.maps.LatLng(p[1], p[0]))
1053
+ });
1054
+
1055
+ for (let i = 0; i < poly2Points.length; i++) {
1056
+ const point = new google.maps.LatLng(poly2Points[i][1], poly2Points[i][0]);
1057
+ if (google.maps.geometry.poly.containsLocation(point, polygon1)) {
1058
+ return true;
1059
+ }
1060
+ }
1061
+
1062
+ for (let i = 0; i < poly1Points.length; i++) {
1063
+ const point = new google.maps.LatLng(poly1Points[i][1], poly1Points[i][0]);
1064
+ if (google.maps.geometry.poly.containsLocation(point, polygon2)) {
1065
+ return true;
1066
+ }
1067
+ }
1068
+
1069
+ return false;
1070
+ }
1071
+
1072
+ function drawPolygonHole(i, config, offsetX, offsetY, vmWidth, isMobile) {
1073
+
1074
+ var path = [];
1075
+
1076
+ path.push(new google.maps.LatLng(hlat + 0.75*2*i*hdppx, hlng - 2*i*wdppx));
1077
+ path.push(new google.maps.LatLng(hlat + 0.75*2*i*hdppx, hlng + 2*i*wdppx));
1078
+ path.push(new google.maps.LatLng(hlat - 0.75*2*i*hdppx, hlng + 2*i*wdppx));
1079
+ path.push(new google.maps.LatLng(hlat - 0.75*2*i*hdppx, hlng - 2*i*wdppx));
1080
+
1081
+ path.reverse();
1082
+
1083
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1084
+
1085
+ var shape = new google.maps.Polygon({
1086
+ //map: map,
1087
+ path: path,
1088
+ id: pid.toString(),
1089
+ content: "",
1090
+ strokeColor: config.strokeColor,
1091
+ strokeOpacity: config.strokeOpacity,
1092
+ strokeWeight: config.strokeWeight,
1093
+ fillColor: config.fillColor,
1094
+ fillOpacity: config.fillOpacity,
1095
+ zIndex: 10200,
1096
+ clickable: true,
1097
+ editable: false,
1098
+ draggable: false,
1099
+ isPolygon: true,
1100
+ isCircle: false,
1101
+ isCircleSector: false,
1102
+ isCircleSegment: false,
1103
+ isHole: true,
1104
+ latitude: 0,
1105
+ longitude: 0,
1106
+ poly: 0,
1107
+ area: 0,
1108
+ perimeter: 0
1109
+ });
1110
+
1111
+ locPolygons.push(shape);
1112
+
1113
+ var osBounds = new google.maps.LatLngBounds();
1114
+ var osPath = locPolygons[0].getPath();
1115
+ osPath.forEach(function(c,index) {
1116
+ osBounds.extend(c);
1117
+ });
1118
+
1119
+ var mapPanned = false;
1120
+
1121
+ var boundsChangedListener = google.maps.event.addListener(map, 'bounds_changed', function () {
1122
+ if(!mapPanned) {
1123
+
1124
+ var psw = map.getProjection().fromLatLngToPoint(osBounds.getSouthWest());
1125
+ var pne = map.getProjection().fromLatLngToPoint(osBounds.getNorthEast());
1126
+
1127
+ var zoom = map.getZoom();
1128
+ var scale = 1 << zoom;
1129
+
1130
+ if((pne.x - psw.x)*scale >= vmWidth) {
1131
+ map.setZoom(zoom-1);
1132
+ }
1133
+
1134
+
1135
+ offsetCenter(osBounds.getCenter(), offsetX, offsetY);
1136
+ mapPanned = !mapPanned;
1137
+
1138
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().edit(map, shape, currentPolygonCustomEdit, isMobile);
1139
+ }
1140
+ });
1141
+ mapListeners.push(boundsChangedListener);
1142
+
1143
+ map.fitBounds(osBounds);
1144
+
1145
+ return pid;
1146
+
1147
+ }
1148
+
1149
+ //#CIRCLE ADD
1150
+ _this.Shape_CircleFull_Add = function (isHole, config, isMobile, mapWidth, mapHeight, vmWidth, vmcLat, vmcLng, offsetX, offsetY) {
1151
+
1152
+ if(!isHole) {
1153
+
1154
+ var startHeading = 0;
1155
+ var endHeading = 360;
1156
+ var mapBounds = map.getBounds();
1157
+ var mapCenter = map.getCenter();
1158
+ var mcLat = mapCenter.lat();
1159
+ var mcLng = mapCenter.lng();
1160
+
1161
+ var cfLat = mcLat, cfLng = mcLng;
1162
+
1163
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1164
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1165
+ wdppx = diffLng/mapWidth;
1166
+ hdppx = diffLat/mapHeight;
1167
+
1168
+ var cfLat = mcLat + offsetY*hdppx;
1169
+ var cfLng = mcLng + offsetX*wdppx;
1170
+
1171
+ var cp = new google.maps.LatLng(cfLat,cfLng);
1172
+
1173
+ var crLat = cfLat;
1174
+ var crLng = cfLng + 80*wdppx;
1175
+
1176
+ var rm = diffLatLng2Meters(cfLat, cfLng, crLat, crLng);
1177
+
1178
+ var shapePath = new IQLCircleFull().get(cfLat, cfLng, rm, startHeading, endHeading);
1179
+
1180
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1181
+
1182
+ var shape = new google.maps.Polygon({
1183
+ map: map,
1184
+ path: shapePath,
1185
+ id: pid.toString(),
1186
+ content: "",
1187
+ strokeColor: config.strokeColor,
1188
+ strokeOpacity: config.strokeOpacity,
1189
+ strokeWeight: config.strokeWeight,
1190
+ fillColor: config.fillColor,
1191
+ fillOpacity: config.fillOpacity,
1192
+ zIndex: 10100,
1193
+ clickable: true,
1194
+ editable: false,
1195
+ draggable: false,
1196
+ visible: false,
1197
+ isPolygon: false,
1198
+ isCircle: true,
1199
+ isCircleSector: false,
1200
+ isCircleSegment: false,
1201
+ isHole: isHole,
1202
+ latitude: 0,
1203
+ longitude: 0,
1204
+ poly: 0,
1205
+ area: 0,
1206
+ perimeter: 0
1207
+ });
1208
+
1209
+ locPolygons.push(shape);
1210
+ currentCircleFull = new IQLCircleFull();
1211
+ currentCircleFull = currentCircleFull.edit(map, shape, currentCircleFull, cp, rm, isMobile, controlMarkers);
1212
+
1213
+ return pid;
1214
+ } else {
1215
+
1216
+ var holeId = addCircleFullHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers);
1217
+
1218
+ return holeId;
1219
+ }
1220
+
1221
+ }
1222
+
1223
+ _this.Shape_CircleSector_Add = function (isHole, config, isMobile, mapWidth, mapHeight, vmWidth, vmcLat, vmcLng, offsetX, offsetY) {
1224
+
1225
+ if(!isHole) {
1226
+
1227
+ var startHeading = 60;
1228
+ var endHeading = 120;
1229
+ var mapBounds = map.getBounds();
1230
+ var mapCenter = map.getCenter();
1231
+ var mcLat = mapCenter.lat();
1232
+ var mcLng = mapCenter.lng();
1233
+
1234
+ var cfLat = mcLat, cfLng = mcLng;
1235
+
1236
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1237
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1238
+ wdppx = diffLng/mapWidth;
1239
+ hdppx = diffLat/mapHeight;
1240
+
1241
+ var cfLat = mcLat + offsetY*hdppx;
1242
+ var cfLng = mcLng + offsetX*wdppx;
1243
+
1244
+ var cp = new google.maps.LatLng(cfLat,cfLng);
1245
+
1246
+ var crLat = cfLat;
1247
+ var crLng = cfLng + 80*wdppx;
1248
+
1249
+ var rm = diffLatLng2Meters(cfLat, cfLng, crLat, crLng);
1250
+
1251
+ var shapePath = new IQLCircleSector().get(cfLat, cfLng, rm, startHeading, endHeading);
1252
+
1253
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1254
+
1255
+ var shape = new google.maps.Polygon({
1256
+ map: map,
1257
+ path: shapePath,
1258
+ id: pid.toString(),
1259
+ content: "",
1260
+ strokeColor: config.strokeColor,
1261
+ strokeOpacity: config.strokeOpacity,
1262
+ strokeWeight: config.strokeWeight,
1263
+ fillColor: config.fillColor,
1264
+ fillOpacity: config.fillOpacity,
1265
+ zIndex: isHole ? 10200 : 10100,
1266
+ clickable: true,
1267
+ editable: false,
1268
+ draggable: false,
1269
+ visible: false,
1270
+ isPolygon: false,
1271
+ isCircle: false,
1272
+ isCircleSector: true,
1273
+ isCircleSegment: false,
1274
+ isHole: isHole,
1275
+ latitude: 0,
1276
+ longitude: 0,
1277
+ poly: 0,
1278
+ area: 0,
1279
+ perimeter: 0
1280
+ });
1281
+
1282
+ locPolygons.push(shape);
1283
+ currentCircleSector = new IQLCircleSector();
1284
+ currentCircleSector = currentCircleSector.edit(map, shape, currentCircleSector, cp, rm, isMobile, controlMarkers);
1285
+
1286
+ return pid;
1287
+
1288
+ } else {
1289
+
1290
+ var holeId = addCircleSectorHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers);
1291
+
1292
+ return holeId;
1293
+
1294
+ }
1295
+ }
1296
+
1297
+ _this.Shape_CircleSegment_Add = function (isHole, config, isMobile, mapWidth, mapHeight, vmWidth, vmcLat, vmcLng, offsetX, offsetY) {
1298
+
1299
+ if(!isHole) {
1300
+
1301
+ var startHeading = 0;
1302
+ var endHeading = 160;
1303
+ var mapBounds = map.getBounds();
1304
+ var mapCenter = map.getCenter();
1305
+ var mcLat = mapCenter.lat();
1306
+ var mcLng = mapCenter.lng();
1307
+
1308
+ var cfLat = mcLat, cfLng = mcLng;
1309
+
1310
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1311
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1312
+ wdppx = diffLng/mapWidth;
1313
+ hdppx = diffLat/mapHeight;
1314
+
1315
+ var cfLat = mcLat + offsetY*hdppx;
1316
+ var cfLng = mcLng + offsetX*wdppx;
1317
+
1318
+ var cp = new google.maps.LatLng(cfLat,cfLng);
1319
+
1320
+ var crLat = cfLat;
1321
+ var crLng = cfLng + 80*wdppx;
1322
+
1323
+ var rm = diffLatLng2Meters(cfLat, cfLng, crLat, crLng);
1324
+
1325
+ var shapePath = new IQLCircleSegment().get(cfLat, cfLng, rm, startHeading, endHeading);
1326
+
1327
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1328
+
1329
+ var shape = new google.maps.Polygon({
1330
+ map: map,
1331
+ path: shapePath,
1332
+ id: pid.toString(),
1333
+ content: "",
1334
+ strokeColor: config.strokeColor,
1335
+ strokeOpacity: config.strokeOpacity,
1336
+ strokeWeight: config.strokeWeight,
1337
+ fillColor: config.fillColor,
1338
+ fillOpacity: config.fillOpacity,
1339
+ zIndex: isHole ? 10200 : 10100,
1340
+ clickable: true,
1341
+ editable: false,
1342
+ draggable: false,
1343
+ visible: false,
1344
+ isPolygon: false,
1345
+ isCircle: false,
1346
+ isCircleSector: false,
1347
+ isCircleSegment: true,
1348
+ isHole: isHole,
1349
+ latitude: 0,
1350
+ longitude: 0,
1351
+ poly: 0,
1352
+ area: 0,
1353
+ perimeter: 0
1354
+ });
1355
+
1356
+ locPolygons.push(shape);
1357
+ currentCircleSegment = new IQLCircleSegment();
1358
+
1359
+ currentCircleSegment = currentCircleSegment.edit(map, shape, currentCircleSegment, cp, rm, isMobile, controlMarkers);
1360
+
1361
+ return pid;
1362
+
1363
+ } else {
1364
+ var holeId = addCircleSegmentHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers);
1365
+
1366
+ return holeId;
1367
+ }
1368
+ }
1369
+
1370
+ //#CIRCLE HOLE
1371
+ function addCircleFullHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers) {
1372
+
1373
+ var nhid;
1374
+
1375
+ if(typeof wdppx == 'undefined' || typeof hdppx == 'undefined') { //this is the case on Select Field or Upload File
1376
+ var mapBounds = map.getBounds();
1377
+
1378
+ if (mapBounds) {
1379
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1380
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1381
+ wdppx = diffLng/mapWidth;
1382
+ hdppx = diffLat/mapHeight;
1383
+ }
1384
+ }
1385
+
1386
+ allPoints = [];
1387
+ locPolygons.forEach(function(lp) {
1388
+ var sPath = lp.getPath();
1389
+ var points = [];
1390
+ for(var c = 0; c < sPath.length; c++) {
1391
+ points.push([sPath.getAt(c).lng(), sPath.getAt(c).lat()]);
1392
+ }
1393
+ if(sPath.getAt(0).lng() != sPath.getAt(sPath.length-1).lng() || sPath.getAt(0).lat() != sPath.getAt(sPath.length-1).lat()) {
1394
+ points.push([sPath.getAt(0).lng(), sPath.getAt(0).lat()]);
1395
+ }
1396
+ allPoints.push(points);
1397
+ });
1398
+
1399
+ var polyCentroidCenter = get_polygon_centroid(allPoints);
1400
+
1401
+ hlat = polyCentroidCenter.y;
1402
+ hlng = polyCentroidCenter.x;
1403
+
1404
+ var startHeading = 0;
1405
+ var endHeading = 360;
1406
+
1407
+ for(var i = 20; i > 0;i--) {
1408
+
1409
+ var hps = [];
1410
+
1411
+ var crLat = hlat;
1412
+ var crLng = hlng + 2*i*wdppx;
1413
+
1414
+ var cp = new google.maps.LatLng(hlat, hlng);
1415
+
1416
+ var rm = diffLatLng2Meters(hlat, hlng, crLat, crLng);
1417
+
1418
+ var shapePath = new IQLCircleFull().get(hlat, hlng, rm, startHeading, endHeading);
1419
+
1420
+ shapePath.forEach(function(sp) {
1421
+ hps.push([sp.lng(), sp.lat()]);
1422
+ });
1423
+
1424
+ allPoints.push(hps);
1425
+
1426
+ var notInsideCount = 0;
1427
+ hps.forEach(function(pt,ptIndex) {
1428
+ if (!google.maps.geometry.poly.containsLocation(new google.maps.LatLng(parseFloat(pt[1]), parseFloat(pt[0])), locPolygons[0])) {
1429
+ notInsideCount++;
1430
+ }
1431
+ });
1432
+
1433
+ if (notInsideCount == 0) {
1434
+
1435
+ if(allPoints.length > 2) {
1436
+ var holeIntersectCount = 0;
1437
+ for (var n = 1; n < allPoints.length - 1; n++) {
1438
+ for (var m = n + 1; m < allPoints.length; m++) {
1439
+ if (calcIntersection(allPoints[n], allPoints[m])) {
1440
+ holeIntersectCount++;
1441
+ }
1442
+ }
1443
+ }
1444
+
1445
+ if(holeIntersectCount == 0) {
1446
+ nhid = drawCircleFullHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1447
+ break;
1448
+ } else {
1449
+ allPoints.pop();
1450
+ }
1451
+ } else {
1452
+ nhid = drawCircleFullHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1453
+ break;
1454
+ }
1455
+ } else {
1456
+ allPoints.pop();
1457
+ }
1458
+ }
1459
+
1460
+ return nhid;
1461
+
1462
+ }
1463
+
1464
+ function addCircleSectorHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers) {
1465
+
1466
+ var nhid;
1467
+
1468
+ if(typeof wdppx == 'undefined' || typeof hdppx == 'undefined') { //this is the case on Select Field or Upload File
1469
+ var mapBounds = map.getBounds();
1470
+
1471
+ if (mapBounds) {
1472
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1473
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1474
+ wdppx = diffLng/mapWidth;
1475
+ hdppx = diffLat/mapHeight;
1476
+ }
1477
+ }
1478
+
1479
+ allPoints = [];
1480
+ locPolygons.forEach(function(lp) {
1481
+ var sPath = lp.getPath();
1482
+ var points = [];
1483
+ for(var c = 0; c < sPath.length; c++) {
1484
+ points.push([sPath.getAt(c).lng(), sPath.getAt(c).lat()]);
1485
+ }
1486
+ if(sPath.getAt(0).lng() != sPath.getAt(sPath.length-1).lng() || sPath.getAt(0).lat() != sPath.getAt(sPath.length-1).lat()) {
1487
+ points.push([sPath.getAt(0).lng(), sPath.getAt(0).lat()]);
1488
+ }
1489
+ allPoints.push(points);
1490
+ });
1491
+
1492
+ var polyCentroidCenter = get_polygon_centroid(allPoints);
1493
+
1494
+ hlat = polyCentroidCenter.y;
1495
+ hlng = polyCentroidCenter.x;
1496
+
1497
+ var startHeading = 60;
1498
+ var endHeading = 120;
1499
+
1500
+ for(var i = 20; i > 0;i--) {
1501
+
1502
+ var hps = [];
1503
+
1504
+ var crLat = hlat;
1505
+ var crLng = hlng + 2*i*wdppx;
1506
+
1507
+ var cp = new google.maps.LatLng(hlat, hlng);
1508
+
1509
+ var rm = diffLatLng2Meters(hlat, hlng, crLat, crLng);
1510
+
1511
+ var shapePath = new IQLCircleSector().get(hlat, hlng, rm, startHeading, endHeading);
1512
+
1513
+ shapePath.forEach(function(sp) {
1514
+ hps.push([sp.lng(), sp.lat()]);
1515
+ });
1516
+
1517
+ allPoints.push(hps);
1518
+
1519
+ var notInsideCount = 0;
1520
+ hps.forEach(function(pt,ptIndex) {
1521
+ if (!google.maps.geometry.poly.containsLocation(new google.maps.LatLng(parseFloat(pt[1]), parseFloat(pt[0])), locPolygons[0])) {
1522
+ notInsideCount++;
1523
+ }
1524
+ });
1525
+
1526
+ if (notInsideCount == 0) { //all points inside outer poly
1527
+
1528
+ if(allPoints.length > 2) {
1529
+ var holeIntersectCount = 0;
1530
+ for (var n = 1; n < allPoints.length - 1; n++) {
1531
+ for (var m = n + 1; m < allPoints.length; m++) {
1532
+ if (calcIntersection(allPoints[n], allPoints[m])) {
1533
+ holeIntersectCount++;
1534
+ }
1535
+ }
1536
+ }
1537
+
1538
+ if(holeIntersectCount == 0) {
1539
+ nhid = drawCircleSectorHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1540
+ break;
1541
+ } else {
1542
+ allPoints.pop();
1543
+ }
1544
+ } else {
1545
+ nhid = drawCircleSectorHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1546
+ break;
1547
+ }
1548
+ } else {
1549
+ allPoints.pop();
1550
+ }
1551
+ }
1552
+
1553
+ return nhid;
1554
+
1555
+ }
1556
+
1557
+ function addCircleSegmentHole(config, mapWidth, mapHeight, offsetX, offsetY, vmWidth, isMobile, controlMarkers) {
1558
+ var nhid;
1559
+
1560
+ if(typeof wdppx == 'undefined' || typeof hdppx == 'undefined') { //this is the case on Select Field or Upload File
1561
+ var mapBounds = map.getBounds();
1562
+
1563
+ if (mapBounds) {
1564
+ diffLat = Math.abs(mapBounds.getSouthWest().lat() - mapBounds.getNorthEast().lat());
1565
+ diffLng = Math.abs(mapBounds.getNorthEast().lng() - mapBounds.getSouthWest().lng());
1566
+ wdppx = diffLng/mapWidth;
1567
+ hdppx = diffLat/mapHeight;
1568
+ }
1569
+ }
1570
+
1571
+ allPoints = [];
1572
+ locPolygons.forEach(function(lp) {
1573
+ var sPath = lp.getPath();
1574
+ var points = [];
1575
+ for(var c = 0; c < sPath.length; c++) {
1576
+ points.push([sPath.getAt(c).lng(), sPath.getAt(c).lat()]);
1577
+ }
1578
+ if(sPath.getAt(0).lng() != sPath.getAt(sPath.length-1).lng() || sPath.getAt(0).lat() != sPath.getAt(sPath.length-1).lat()) {
1579
+ points.push([sPath.getAt(0).lng(), sPath.getAt(0).lat()]);
1580
+ }
1581
+ allPoints.push(points);
1582
+ });
1583
+
1584
+ var polyCentroidCenter = get_polygon_centroid(allPoints);
1585
+
1586
+ hlat = polyCentroidCenter.y;
1587
+ hlng = polyCentroidCenter.x;
1588
+
1589
+ var startHeading = 0;
1590
+ var endHeading = 160;
1591
+
1592
+ for(var i = 20; i > 0;i--) {
1593
+
1594
+ var hps = [];
1595
+
1596
+ var crLat = hlat;
1597
+ var crLng = hlng + 2*i*wdppx;
1598
+
1599
+ var cp = new google.maps.LatLng(hlat, hlng);
1600
+
1601
+ var rm = diffLatLng2Meters(hlat, hlng, crLat, crLng);
1602
+
1603
+ var shapePath = new IQLCircleSector().get(hlat, hlng, rm, startHeading, endHeading);
1604
+
1605
+ shapePath.forEach(function(sp) {
1606
+ hps.push([sp.lng(), sp.lat()]);
1607
+ });
1608
+
1609
+ allPoints.push(hps);
1610
+
1611
+ var notInsideCount = 0;
1612
+ hps.forEach(function(pt,ptIndex) {
1613
+ if (!google.maps.geometry.poly.containsLocation(new google.maps.LatLng(parseFloat(pt[1]), parseFloat(pt[0])), locPolygons[0])) {
1614
+ notInsideCount++;
1615
+ }
1616
+ });
1617
+
1618
+ if (notInsideCount == 0) { //all points inside outer poly
1619
+
1620
+ if(allPoints.length > 2) {
1621
+ var holeIntersectCount = 0;
1622
+ for (var n = 1; n < allPoints.length - 1; n++) {
1623
+ for (var m = n + 1; m < allPoints.length; m++) {
1624
+ if (calcIntersection(allPoints[n], allPoints[m])) {
1625
+ holeIntersectCount++;
1626
+ }
1627
+ }
1628
+ }
1629
+
1630
+ if(holeIntersectCount == 0) {
1631
+ nhid = drawCircleSegmentHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1632
+ break;
1633
+ } else {
1634
+ allPoints.pop();
1635
+ }
1636
+ } else {
1637
+ nhid = drawCircleSegmentHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers);
1638
+ break;
1639
+ }
1640
+ } else {
1641
+ allPoints.pop();
1642
+ }
1643
+ }
1644
+
1645
+ return nhid;
1646
+
1647
+ }
1648
+
1649
+ function drawCircleFullHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers) {
1650
+
1651
+ var path = [];
1652
+ shapePath.forEach(function(sp) {
1653
+ path.push(new google.maps.LatLng(sp.lat(), sp.lng()));
1654
+ });
1655
+
1656
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1657
+
1658
+ var shape = new google.maps.Polygon({
1659
+ map: map,
1660
+ path: path,
1661
+ id: pid.toString(),
1662
+ content: "",
1663
+ strokeColor: config.strokeColor,
1664
+ strokeOpacity: config.strokeOpacity,
1665
+ strokeWeight: config.strokeWeight,
1666
+ fillColor: config.fillColor,
1667
+ fillOpacity: config.fillOpacity,
1668
+ zIndex: 10200,
1669
+ clickable: true,
1670
+ editable: false,
1671
+ draggable: false,
1672
+ visible: false,
1673
+ isPolygon: false,
1674
+ isCircle: true,
1675
+ isCircleSector: false,
1676
+ isCircleSegment: false,
1677
+ isHole: true,
1678
+ latitude: 0,
1679
+ longitude: 0,
1680
+ poly: 0,
1681
+ area: 0,
1682
+ perimeter: 0
1683
+ });
1684
+
1685
+ locPolygons.push(shape);
1686
+ currentCircleFull = new IQLCircleFull();
1687
+ currentCircleFull = currentCircleFull.edit(map, shape, currentCircleFull, cp, rm, isMobile, controlMarkers);
1688
+
1689
+ var osBounds = new google.maps.LatLngBounds();
1690
+ var osPath = locPolygons[0].getPath();
1691
+ osPath.forEach(function(c,index) {
1692
+ osBounds.extend(c);
1693
+ });
1694
+
1695
+ var mapPanned = false;
1696
+
1697
+ var boundsChangedListener = google.maps.event.addListener(map, 'bounds_changed', function () {
1698
+
1699
+ if(!mapPanned) {
1700
+
1701
+ var psw = map.getProjection().fromLatLngToPoint(osBounds.getSouthWest());
1702
+ var pne = map.getProjection().fromLatLngToPoint(osBounds.getNorthEast());
1703
+
1704
+ var zoom = map.getZoom();
1705
+ var scale = 1 << zoom;
1706
+
1707
+ if((pne.x - psw.x)*scale >= vmWidth) {
1708
+ map.setZoom(zoom-1);
1709
+ }
1710
+
1711
+ offsetCenter(osBounds.getCenter(), offsetX, offsetY);
1712
+ mapPanned = !mapPanned;
1713
+ }
1714
+ });
1715
+ mapListeners.push(boundsChangedListener);
1716
+
1717
+ map.fitBounds(osBounds);
1718
+
1719
+ return pid;
1720
+
1721
+ }
1722
+
1723
+ function drawCircleSectorHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers) {
1724
+
1725
+ var path = [];
1726
+ shapePath.forEach(function(sp) {
1727
+ path.push(new google.maps.LatLng(sp.lat(), sp.lng()));
1728
+ });
1729
+
1730
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1731
+
1732
+ var shape = new google.maps.Polygon({
1733
+ map: map,
1734
+ path: path,
1735
+ id: pid.toString(),
1736
+ content: "",
1737
+ strokeColor: config.strokeColor,
1738
+ strokeOpacity: config.strokeOpacity,
1739
+ strokeWeight: config.strokeWeight,
1740
+ fillColor: config.fillColor,
1741
+ fillOpacity: config.fillOpacity,
1742
+ zIndex: 10200,
1743
+ clickable: true,
1744
+ editable: false,
1745
+ draggable: false,
1746
+ visible: false,
1747
+ isPolygon: false,
1748
+ isCircle: false,
1749
+ isCircleSector: true,
1750
+ isCircleSegment: false,
1751
+ isHole: true,
1752
+ latitude: 0,
1753
+ longitude: 0,
1754
+ poly: 0,
1755
+ area: 0,
1756
+ perimeter: 0
1757
+ });
1758
+
1759
+ locPolygons.push(shape);
1760
+ currentCircleSector = new IQLCircleSector();
1761
+
1762
+ currentCircleSector = currentCircleSector.edit(map, shape, currentCircleSector, cp, rm, isMobile, controlMarkers);
1763
+
1764
+ var osBounds = new google.maps.LatLngBounds();
1765
+ var osPath = locPolygons[0].getPath();
1766
+ osPath.forEach(function(c,index) {
1767
+ osBounds.extend(c);
1768
+ });
1769
+
1770
+ var mapPanned = false;
1771
+
1772
+ var boundsChangedListener = google.maps.event.addListener(map, 'bounds_changed', function () {
1773
+
1774
+ //console.log('CircleSectorHole, map bounds changed');
1775
+
1776
+ if(!mapPanned) {
1777
+
1778
+ var psw = map.getProjection().fromLatLngToPoint(osBounds.getSouthWest());
1779
+ var pne = map.getProjection().fromLatLngToPoint(osBounds.getNorthEast());
1780
+
1781
+ var zoom = map.getZoom();
1782
+ var scale = 1 << zoom;
1783
+
1784
+ if((pne.x - psw.x)*scale >= vmWidth) {
1785
+ map.setZoom(zoom-1);
1786
+ }
1787
+
1788
+ offsetCenter(osBounds.getCenter(), offsetX, offsetY);
1789
+ mapPanned = !mapPanned;
1790
+ }
1791
+ });
1792
+ mapListeners.push(boundsChangedListener);
1793
+
1794
+ map.fitBounds(osBounds);
1795
+
1796
+ return pid;
1797
+
1798
+ }
1799
+
1800
+ function drawCircleSegmentHole(config, offsetX, offsetY, vmWidth, shapePath, cp, rm, isMobile, controlMarkers) {
1801
+
1802
+ var path = [];
1803
+ shapePath.forEach(function(sp) {
1804
+ path.push(new google.maps.LatLng(sp.lat(), sp.lng()));
1805
+ });
1806
+
1807
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
1808
+
1809
+ var shape = new google.maps.Polygon({
1810
+ map: map,
1811
+ path: path,
1812
+ id: pid.toString(),
1813
+ content: "",
1814
+ strokeColor: config.strokeColor,
1815
+ strokeOpacity: config.strokeOpacity,
1816
+ strokeWeight: config.strokeWeight,
1817
+ fillColor: config.fillColor,
1818
+ fillOpacity: config.fillOpacity,
1819
+ zIndex: 10200,
1820
+ clickable: true,
1821
+ editable: false,
1822
+ draggable: false,
1823
+ visible: false,
1824
+ isPolygon: false,
1825
+ isCircle: false,
1826
+ isCircleSector: false,
1827
+ isCircleSegment: true,
1828
+ isHole: true,
1829
+ latitude: 0,
1830
+ longitude: 0,
1831
+ poly: 0,
1832
+ area: 0,
1833
+ perimeter: 0
1834
+ });
1835
+
1836
+ locPolygons.push(shape);
1837
+ currentCircleSegment = new IQLCircleSegment();
1838
+
1839
+ currentCircleSegment = currentCircleSegment.edit(map, shape, currentCircleSegment, cp, rm, isMobile, controlMarkers);
1840
+
1841
+ var osBounds = new google.maps.LatLngBounds();
1842
+ var osPath = locPolygons[0].getPath();
1843
+ osPath.forEach(function(c,index) {
1844
+ osBounds.extend(c);
1845
+ });
1846
+
1847
+ var mapPanned = false;
1848
+
1849
+ var boundsChangedListener = google.maps.event.addListener(map, 'bounds_changed', function () {
1850
+
1851
+ if(!mapPanned) {
1852
+
1853
+ var psw = map.getProjection().fromLatLngToPoint(osBounds.getSouthWest());
1854
+ var pne = map.getProjection().fromLatLngToPoint(osBounds.getNorthEast());
1855
+
1856
+ var zoom = map.getZoom();
1857
+ var scale = 1 << zoom;
1858
+
1859
+ if((pne.x - psw.x)*scale >= vmWidth) {
1860
+ map.setZoom(zoom-1);
1861
+ }
1862
+
1863
+ offsetCenter(osBounds.getCenter(), offsetX, offsetY);
1864
+ mapPanned = !mapPanned;
1865
+ }
1866
+ });
1867
+ mapListeners.push(boundsChangedListener);
1868
+
1869
+ map.fitBounds(osBounds);
1870
+
1871
+ return pid;
1872
+
1873
+ }
1874
+
1875
+ function offsetCenter(latlng, offsetX, offsetY) {
1876
+
1877
+ var zoom = map.getZoom();
1878
+ var scale = 1 << zoom;
1879
+ var worldCoordinateCenter = map.getProjection().fromLatLngToPoint(latlng);
1880
+ var pixelOffset = new google.maps.Point((offsetX/scale) || 0,(offsetY/scale) || 0);
1881
+
1882
+ var worldCoordinateNewCenter = new google.maps.Point(
1883
+ worldCoordinateCenter.x - pixelOffset.x,
1884
+ worldCoordinateCenter.y + pixelOffset.y
1885
+ );
1886
+
1887
+ var newCenter = map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);
1888
+
1889
+ map.setCenter(newCenter);
1890
+
1891
+ }
1892
+
1893
+ _this.RenderRegionFarms = function (locationsJson, icon) {
1894
+ if(icon){
1895
+ AdvancedMarker(locationsJson, icon, 'farm');
1896
+ }
1897
+ }
1898
+
1899
+ _this.TriggerField_ChangeEvent = function () {
1900
+ var area = 0;
1901
+ var perimeter = 0;
1902
+ var path = '';
1903
+ var latitude = 0;
1904
+ var longitude = 0;
1905
+ var bounds = new google.maps.LatLngBounds();
1906
+ var isValid = "";
1907
+ var polyPath = [];
1908
+
1909
+ locPolygons.forEach(function (polygon, index) {
1910
+ var poly;
1911
+ poly = polygon.getPath();
1912
+
1913
+ ({ perimeter, area, path } = fieldArea_calculate(index, poly, bounds, perimeter, area, path));
1914
+ polyPath.push({path: path.split(',')[index], isHole: polygon.isHole});
1915
+ });
1916
+
1917
+ path = path.substr(0, path.length - 1);
1918
+ if (path !== "") {
1919
+ console.log('Checking field overlaps...');
1920
+ if (!_this.checkForBackgroundFieldOverlaps()) {
1921
+ console.log('Overlap detected - setting error message');
1922
+ isValid = "Error: Field overlaps with an existing field";
1923
+ }
1924
+ }
1925
+
1926
+ area = -area;
1927
+ latitude = parseFloat(bounds.getCenter().lat());
1928
+ longitude = parseFloat(bounds.getCenter().lng());
1929
+
1930
+ return new IQLFieldGeoLocation(path, area, perimeter, latitude, longitude, isValid);
1931
+ }
1932
+
1933
+ function fieldArea_calculate(index, poly, bounds, perimeter, area, path) {
1934
+ var mapCoords = [];
1935
+ var i;
1936
+
1937
+ if (index === 0) {
1938
+
1939
+ for (i = 0; i < poly.getLength(); i++) {
1940
+ mapCoords.push(poly.getAt(i));
1941
+ bounds.extend(poly.getAt(i));
1942
+ if (i < poly.getLength() - 1) {
1943
+ perimeter += google.maps.geometry.spherical.computeDistanceBetween(poly.getAt(i), poly.getAt(i + 1));
1944
+ }
1945
+ }
1946
+
1947
+ if (mapCoords[0].lat() != mapCoords[mapCoords.length - 1].lat() && mapCoords[0].lng() != mapCoords[mapCoords.length - 1].lng()) {
1948
+ mapCoords.push(mapCoords[0]);
1949
+ }
1950
+
1951
+ if (google.maps.geometry.spherical.computeSignedArea(mapCoords) > 0) {
1952
+ mapCoords.reverse();
1953
+ }
1954
+
1955
+ area += google.maps.geometry.spherical.computeSignedArea(mapCoords);
1956
+ path = google.maps.geometry.encoding.encodePath(mapCoords) + ',';
1957
+
1958
+ } else {
1959
+
1960
+ for (i = 0; i < poly.getLength(); i++) {
1961
+ mapCoords.push(poly.getAt(i));
1962
+ bounds.extend(poly.getAt(i));
1963
+ if (i < poly.getLength() - 1) {
1964
+ perimeter += google.maps.geometry.spherical.computeDistanceBetween(poly.getAt(i), poly.getAt(i + 1));
1965
+ }
1966
+ }
1967
+
1968
+ area += google.maps.geometry.spherical.computeSignedArea(mapCoords);
1969
+ path += google.maps.geometry.encoding.encodePath(mapCoords) + ',';
1970
+
1971
+ }
1972
+ return { perimeter, area, path };
1973
+ }
1974
+
1975
+ _this.DrawField_AttachEvents = function (eHandlers) {
1976
+
1977
+ locPolygons.forEach(function (polygon) {
1978
+
1979
+ var moverListener = google.maps.event.addListener(polygon, 'mouseover', function () {
1980
+ eHandlers["JS_ShapeOnMouseIn"](this.id);
1981
+ });
1982
+ polygonListeners.push(moverListener);
1983
+
1984
+ var moutListener = google.maps.event.addListener(polygon, 'mouseout', function () {
1985
+ eHandlers["JS_ShapeOnMouseOut"](this.id);
1986
+ });
1987
+ polygonListeners.push(moutListener);
1988
+
1989
+ var mclListener = google.maps.event.addListener(polygon, 'click', function () {
1990
+ eHandlers["ShapeSelect"](this.id);
1991
+ });
1992
+ polygonListeners.push(mclListener);
1993
+ });
1994
+
1995
+ }
1996
+
1997
+ _this.PolygonCustomEdit_Edit = function (ShapeId, isMobile) {
1998
+ var polygonCE = locPolygons.find(p => p.id == ShapeId);
1999
+ if (polygonCE) {
2000
+
2001
+ var pcePath = polygonCE.getPath();
2002
+ if(pcePath.getAt(0).lat() == pcePath.getAt(pcePath.getLength()-1).lat() && pcePath.getAt(0).lng() == pcePath.getAt(pcePath.getLength()-1).lng()) {
2003
+ pcePath.pop();
2004
+ }
2005
+
2006
+ polygonCE.setPath(pcePath);
2007
+ polygonCE.setMap(null);
2008
+ currentPolygonCustomEdit = new IQLPolygonCustomEdit().edit(map, polygonCE, currentPolygonCustomEdit, isMobile);
2009
+ }
2010
+ }
2011
+
2012
+ _this.CircleSector_Edit = function (ShapeId, isMobile) {
2013
+ var circleSec = locPolygons.find(p => p.id == ShapeId);
2014
+
2015
+ if (circleSec) {
2016
+ // Delete the original shape
2017
+ //_this.Shape_Delete(ShapeId);
2018
+
2019
+ // Calculate center point from the polygon's bounds
2020
+ var bounds = new google.maps.LatLngBounds();
2021
+ circleSec.getPath().forEach(point => bounds.extend(point));
2022
+ var centerPoint = bounds.getCenter();
2023
+
2024
+ // Calculate radius as distance from center to first point
2025
+ var initialRadius = google.maps.geometry.spherical.computeDistanceBetween(
2026
+ centerPoint,
2027
+ circleSec.getPath().getAt(0)
2028
+ );
2029
+
2030
+ currentCircleSector = new IQLCircleSector().edit(
2031
+ map,
2032
+ circleSec,
2033
+ currentCircleSector,
2034
+ centerPoint,
2035
+ initialRadius,
2036
+ isMobile,
2037
+ controlMarkers
2038
+ );
2039
+ }
2040
+ }
2041
+
2042
+
2043
+ _this.CircleFull_Edit = function (ShapeId, isMobile) {
2044
+ var circleFull = locPolygons.find(p => p.id == ShapeId);
2045
+
2046
+ if (circleFull) {
2047
+
2048
+ var bounds = new google.maps.LatLngBounds();
2049
+ circleFull.getPath().forEach(point => bounds.extend(point));
2050
+ var centerPoint = bounds.getCenter();
2051
+
2052
+ var initialRadius = google.maps.geometry.spherical.computeDistanceBetween(
2053
+ centerPoint,
2054
+ circleFull.getPath().getAt(0)
2055
+ );
2056
+
2057
+ currentCircleFull = new IQLCircleFull().edit(
2058
+ map,
2059
+ circleFull,
2060
+ currentCircleFull,
2061
+ centerPoint,
2062
+ initialRadius,
2063
+ isMobile,
2064
+ controlMarkers
2065
+ );
2066
+ }
2067
+ }
2068
+
2069
+ _this.CircleSegment_Edit = function (ShapeId, isMobile) {
2070
+ var circleSeg = locPolygons.find(p => p.id == ShapeId);
2071
+
2072
+ if (circleSeg) {
2073
+ // Delete the original shape
2074
+ _this.Shape_Delete(ShapeId);
2075
+
2076
+ // Calculate center point from the polygon's bounds
2077
+ var bounds = new google.maps.LatLngBounds();
2078
+ circleSeg.getPath().forEach(point => bounds.extend(point));
2079
+ var centerPoint = bounds.getCenter();
2080
+
2081
+ // Calculate radius as distance from center to first point
2082
+ var initialRadius = google.maps.geometry.spherical.computeDistanceBetween(
2083
+ centerPoint,
2084
+ circleSeg.getPath().getAt(0)
2085
+ );
2086
+
2087
+ currentCircleSegment = new IQLCircleSegment().edit(
2088
+ map,
2089
+ circleSeg,
2090
+ currentCircleSegment,
2091
+ centerPoint,
2092
+ initialRadius,
2093
+ isMobile,
2094
+ controlMarkers
2095
+ );
2096
+ }
2097
+ }
2098
+
2099
+ _this.RenderRegions = function (locations, properties) {
2100
+ var polygon = null;
2101
+ var polyPath = null;
2102
+ var path = null;
2103
+ fpolies = [];
2104
+ var rbounds = new google.maps.LatLngBounds();
2105
+
2106
+ locations.forEach(function (location) {
2107
+
2108
+ const hasId = typeof location.Id === "string"
2109
+ ? location.Id.length > 0
2110
+ : typeof location.Id === "number" && location.Id > 0;
2111
+
2112
+ if (location && hasId) {
2113
+ var polies = [];
2114
+ if(!location.Poly.length > 0){
2115
+ polies = location.Coords;
2116
+ }
2117
+ else{
2118
+ polies = location.Poly.split(',');
2119
+ }
2120
+
2121
+ var paths = [];
2122
+
2123
+ polies.forEach(function (poly, pIndex) {
2124
+ if(!location.Poly.length > 0){
2125
+ //geoJson
2126
+ path = [];
2127
+ poly.forEach(function (v) {
2128
+ path.push(new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])));
2129
+ rbounds.extend(new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])));
2130
+ });
2131
+ paths.push(path);
2132
+ } else {
2133
+ //encoded polyline
2134
+ polyPath = polyline.decode(poly);
2135
+ path = [];
2136
+ polyPath.forEach(function (v) {
2137
+ path.push(new google.maps.LatLng(parseFloat(v[0]), parseFloat(v[1])));
2138
+ rbounds.extend(new google.maps.LatLng(parseFloat(v[0]), parseFloat(v[1])));
2139
+ });
2140
+ paths.push(path);
2141
+ }
2142
+ });
2143
+
2144
+ var polygonOptions = {
2145
+ ...properties.polygonOptions.unselected,
2146
+ paths: paths,
2147
+ id: location.Id,
2148
+ content: location.LocationName,
2149
+ map: map
2150
+ }
2151
+
2152
+ polygon = new google.maps.Polygon(polygonOptions);
2153
+ fpolies.push(polygon);
2154
+ }
2155
+ });
2156
+ map.fitBounds(rbounds);
2157
+ regions_BindPolyEvents();
2158
+ }
2159
+
2160
+ _this.Shape_Convert = function (ShapeId) {
2161
+ locPolygons.forEach(function (p) {
2162
+ if (p.id == ShapeId) {
2163
+ if (!p.isPolygon) {
2164
+
2165
+ var shape;
2166
+ var pid = Date.now() + Math.floor(Math.random() * 100000);
2167
+
2168
+ if (p.isCircle) {
2169
+ var shapePaths = circleToPolygon([p.getCenter().lng(), p.getCenter().lat()], p.getRadius(), 72, p.isHole);
2170
+ shape = new google.maps.Polygon({
2171
+ map: p.map,
2172
+ path: shapePaths,
2173
+ id: pid,
2174
+ content: p.content,
2175
+ strokeColor: p.strokeColor,
2176
+ strokeOpacity: p.strokeOpacity,
2177
+ strokeWeight: p.strokeWeight,
2178
+ fillColor: p.fillColor,
2179
+ fillOpacity: p.fillOpacity,
2180
+ zIndex: p.zIndex,
2181
+ clickable: p.clickable,
2182
+ editable: p.editable,
2183
+ draggable: p.draggable,
2184
+ visible: false,
2185
+ isPolygon: true,
2186
+ isCircle: false,
2187
+ isCircleSector: false,
2188
+ isCircleSegment: false,
2189
+ isHole: p.isHole,
2190
+ latitude: p.latitude,
2191
+ longitude: p.longitude,
2192
+ poly: p.poly,
2193
+ area: p.area,
2194
+ perimeter: p.perimeter
2195
+ });
2196
+
2197
+ } else if (p.isCircleSector) {
2198
+
2199
+ shape = new google.maps.Polygon({
2200
+ map: p.map,
2201
+ paths: p.paths,
2202
+ id: pid,
2203
+ content: p.content,
2204
+ strokeColor: p.strokeColor,
2205
+ strokeOpacity: p.strokeOpacity,
2206
+ strokeWeight: p.strokeWeight,
2207
+ fillColor: p.fillColor,
2208
+ fillOpacity: p.fillOpacity,
2209
+ zIndex: p.zIndex,
2210
+ clickable: p.clickable,
2211
+ editable: p.editable,
2212
+ draggable: p.draggable,
2213
+ visible: false,
2214
+ isPolygon: true,
2215
+ isCircle: false,
2216
+ isCircleSector: false,
2217
+ isCircleSegment: false,
2218
+ isHole: p.isHole,
2219
+ latitude: p.latitude,
2220
+ longitude: p.longitude,
2221
+ poly: p.poly,
2222
+ area: p.area,
2223
+ perimeter: p.perimeter
2224
+ });
2225
+
2226
+ } else if (p.isCircleSegment) {
2227
+
2228
+ shape = new google.maps.Polygon({
2229
+ map: p.map,
2230
+ paths: p.paths,
2231
+ id: pid,
2232
+ content: p.content,
2233
+ strokeColor: p.strokeColor,
2234
+ strokeOpacity: p.strokeOpacity,
2235
+ strokeWeight: p.strokeWeight,
2236
+ fillColor: p.fillColor,
2237
+ fillOpacity: p.fillOpacity,
2238
+ zIndex: p.zIndex,
2239
+ clickable: p.clickable,
2240
+ editable: p.editable,
2241
+ draggable: p.draggable,
2242
+ visible: false,
2243
+ isPolygon: true,
2244
+ isCircle: false,
2245
+ isCircleSector: false,
2246
+ isCircleSegment: true,
2247
+ isHole: p.isHole,
2248
+ latitude: p.latitude,
2249
+ longitude: p.longitude,
2250
+ poly: p.poly,
2251
+ area: p.area,
2252
+ perimeter: p.perimeter
2253
+ });
2254
+
2255
+ }
2256
+
2257
+ locPolygons.push(shape);
2258
+
2259
+ return pid;
2260
+ }
2261
+ }
2262
+ });
2263
+ }
2264
+
2265
+ _this.addToLocPolygons = function(shape) {
2266
+ locPolygons = [];
2267
+ locPolygons.push(shape);
2268
+ };
2269
+
2270
+ _this.RenderBackgroundFields = function (locations, properties) {
2271
+ var mbounds = new google.maps.LatLngBounds();
2272
+
2273
+ backgroundFields.forEach(field => {
2274
+ field.setMap(null);
2275
+ });
2276
+ backgroundFields = [];
2277
+
2278
+ locations.forEach(function (location) {
2279
+ if (location && location.Poly && location.Poly.length > 0 && location.Id.length > 0) {
2280
+ var paths = location.Poly.map(poly =>
2281
+ poly.map(v => new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])))
2282
+ );
2283
+ paths[0].forEach(coord => mbounds.extend(coord));
2284
+
2285
+ let content = `${location.FarmName} - ${location.LocationName}<br>${location.Area} ha${location.IsIrrigated ? ', irrigated' : ''}`;
2286
+
2287
+ if (location.CropPlanted) {
2288
+ content += `<br>${location.CropPlanted}`;
2289
+ if (location.CultivarPlanted) {
2290
+ content += ` (${location.CultivarPlanted})`;
2291
+ }
2292
+ if (location.PlantingDate) {
2293
+ content += `<br>Planted: ${location.PlantingDate.replace(/-/g, "/")}`;
2294
+ }
2295
+ }
2296
+
2297
+ var polygonOptions = {
2298
+ ...properties.polygonOptions.other,
2299
+ paths: paths,
2300
+ id: location.Id,
2301
+ content: content,
2302
+ map: map
2303
+ }
2304
+
2305
+ var polygon = new google.maps.Polygon(polygonOptions);
2306
+ backgroundFields.push(polygon);
2307
+ }
2308
+ });
2309
+
2310
+ map.fitBounds(mbounds);
2311
+ };
2312
+
2313
+ _this.clearBackgroundFields = function() {
2314
+ backgroundFields.forEach(field => {
2315
+ field.setMap(null);
2316
+ });
2317
+ backgroundFields = [];
2318
+ };
2319
+
2320
+ _this.checkForBackgroundFieldOverlaps = function() {
2321
+ console.log('Checking overlaps - Background Fields:', backgroundFields.length, 'Local Polygons:', locPolygons.length);
2322
+
2323
+ if (!backgroundFields.length || !locPolygons.length) {
2324
+ console.log('No fields to check for overlap');
2325
+ return true;
2326
+ }
2327
+
2328
+ for (const locPolygon of locPolygons) {
2329
+ for (const bgField of backgroundFields) {
2330
+ const locPath = locPolygon.getPath().getArray();
2331
+ const bgPath = bgField.getPath().getArray();
2332
+
2333
+ for (const point of locPath) {
2334
+ if (google.maps.geometry.poly.containsLocation(point, bgField)) {
2335
+ console.log('Overlap detected: Local polygon point inside background field');
2336
+ return false;
2337
+ }
2338
+ }
2339
+
2340
+ for (const point of bgPath) {
2341
+ if (google.maps.geometry.poly.containsLocation(point, locPolygon)) {
2342
+ console.log('Overlap detected: Background field point inside local polygon');
2343
+ return false;
2344
+ }
2345
+ }
2346
+ }
2347
+ }
2348
+
2349
+ console.log('No overlaps detected');
2350
+ return true;
2351
+ };
2352
+
2353
+ _this.NDVI_AddOverlay_DEA = function (locationJson, ndviTileURL, validGMTiles, eosLocationCropperRefId, eosViewId, spinnerURL, spinnerLat, spinnerLon, paletteId, colorMapTypeIdValue, isFullView, onComplete) {
2354
+ var locationParsed = locationJson;
2355
+ var location = locationParsed[0];
2356
+ var centerLat, centerLng;
2357
+ var polyBounds = new google.maps.LatLngBounds();
2358
+
2359
+ if (location && location.Poly && location.Poly.length > 0 && location.Id > 0) {
2360
+ var centroid = get_polygon_centroid(location.Poly);
2361
+ centerLat = centroid.y;
2362
+ centerLng = centroid.x;
2363
+
2364
+ location.Poly.forEach(function (poly, pIndex) {
2365
+ poly.forEach(function (v) {
2366
+ if(pIndex == 0) {
2367
+ polyBounds.extend(new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])));
2368
+ }
2369
+ });
2370
+ });
2371
+
2372
+ } else {
2373
+ centerLat = spinnerLat;
2374
+ centerLng = spinnerLon;
2375
+ }
2376
+
2377
+ var vgmTilesIn = validGMTiles;
2378
+
2379
+ var fullView = 0;
2380
+ if(isFullView) {
2381
+ fullView = 1;
2382
+ }
2383
+
2384
+ var vgmTiles = vgmTilesIn;
2385
+
2386
+ console.log(vgmTiles);
2387
+
2388
+ var spinnerSet = false;
2389
+
2390
+ if(!spinnerSet) {
2391
+ const spinnerImg = document.createElement('img');
2392
+ spinnerImg.src = spinnerURL;
2393
+ spinnerImg.width = 120;
2394
+ spinnerImg.height = 120;
2395
+ spinnerImg.style.transform = 'translate(0, 50%)';
2396
+ const position = new google.maps.LatLng(centerLat, centerLng);
2397
+
2398
+ var spinnerMarker = new google.maps.marker.AdvancedMarkerElement({
2399
+ map: map,
2400
+ position: position,
2401
+ content: spinnerImg,
2402
+ });
2403
+ fmarkers.push(spinnerMarker);
2404
+ spinnerSet = true;
2405
+ }
2406
+
2407
+ var tilesToLoad = [];
2408
+
2409
+ if (map.getZoom() > 17) {
2410
+ var zoomOnAddOverlayChangedListener = google.maps.event.addListenerOnce(map, 'zoom_changed', function () {
2411
+ tilesToLoad = [];
2412
+
2413
+ var vdiMapType = new google.maps.ImageMapType({
2414
+ getTileUrl: function (coord, zoom) {
2415
+ if(vgmTiles.indexOf(zoom+'|'+coord.x+'|'+coord.y) > -1) {
2416
+ const booleanFullView = fullView ? 'true' : 'false';
2417
+ console.log([ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join(''));
2418
+ tilesToLoad.push({eosLocationCropperRefId: eosLocationCropperRefId, eosViewId: eosViewId, z: zoom});
2419
+ return [ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join('');
2420
+ }
2421
+ },
2422
+ tileSize: new google.maps.Size(256, 256),
2423
+ minZoom: 13,
2424
+ maxZoom: 17
2425
+ });
2426
+
2427
+ vdiMapType.addListener("tilesloaded", function() {
2428
+ if(spinnerSet) {
2429
+ fmarkers.forEach(function(l,index) {
2430
+ //if(l.id == 'spinnerMarker') {
2431
+ l.setMap(null);
2432
+ fmarkers.splice(index, 1);
2433
+ spinnerSet = false;
2434
+ //}
2435
+ });
2436
+ }
2437
+
2438
+
2439
+ var fullView = false;
2440
+ if(tilesToLoad.length > 0) {
2441
+ if(tilesToLoad[0].fullView == 1) {
2442
+ fullView = true;
2443
+ }
2444
+ }
2445
+
2446
+ if (typeof onComplete === 'function') {
2447
+ if(tilesToLoad.length > 0) {
2448
+ const currentZoom = map.getZoom();
2449
+ let zoomTileCount = 0;
2450
+ validGMTiles.forEach((tile) => {
2451
+ if(parseInt(tile.substring(0,tile.indexOf('|'))) == currentZoom ) {
2452
+ zoomTileCount++;
2453
+ }
2454
+ })
2455
+ if(tilesToLoad.length == zoomTileCount) {
2456
+ eventHandlers["OverlayTilesLoaded"]({
2457
+ type: 'SUCCESS',
2458
+ message: 'NDVI overlay completed',
2459
+ code: 200,
2460
+ data: tilesToLoad[0]
2461
+ });
2462
+ } else {
2463
+ eventHandlers["OverlayTilesLoaded"]({
2464
+ type: 'ERROR',
2465
+ message: 'Not all tiles loaded',
2466
+ code: 400,
2467
+ data: null
2468
+ });
2469
+ }
2470
+ } else {
2471
+ eventHandlers["OverlayTilesLoaded"]({
2472
+ type: 'ERROR',
2473
+ message: 'No tiles loaded',
2474
+ code: 400,
2475
+ data: null
2476
+ });
2477
+ }
2478
+ }
2479
+
2480
+ tilesToLoad = [];
2481
+
2482
+ });
2483
+
2484
+ map.overlayMapTypes.push(vdiMapType);
2485
+ });
2486
+ mapListeners.push(zoomOnAddOverlayChangedListener);
2487
+
2488
+ map.setZoom(17);
2489
+
2490
+ } else if (map.getZoom() < 13) {
2491
+ var zoomOnAddOverlayChangedListener = google.maps.event.addListenerOnce(map, 'zoom_changed', function () {
2492
+
2493
+ tilesToLoad = [];
2494
+
2495
+ var vdiMapType = new google.maps.ImageMapType({
2496
+ getTileUrl: function (coord, zoom) {
2497
+ if(vgmTiles.indexOf(zoom+'|'+coord.x+'|'+coord.y) > -1) {
2498
+ const booleanFullView = fullView ? 'true' : 'false';
2499
+ console.log([ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join(''));
2500
+ tilesToLoad.push({eosLocationCropperRefId: eosLocationCropperRefId, eosViewId: eosViewId, z: zoom});
2501
+ return [ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join('');
2502
+ }
2503
+ },
2504
+ tileSize: new google.maps.Size(256, 256),
2505
+ minZoom: 13,
2506
+ maxZoom: 17
2507
+ });
2508
+
2509
+ vdiMapType.addListener("tilesloaded", function() {
2510
+ if(spinnerSet) {
2511
+ fmarkers.forEach(function(l,index) {
2512
+ //if(l.id == 'spinnerMarker') {
2513
+ l.setMap(null);
2514
+ fmarkers.splice(index, 1);
2515
+ spinnerSet = false;
2516
+ //}
2517
+ });
2518
+ }
2519
+
2520
+ var fullView = false;
2521
+ if(tilesToLoad.length > 0) {
2522
+ if(tilesToLoad[0].fullView == 1) {
2523
+ fullView = true;
2524
+ }
2525
+ }
2526
+
2527
+ //if (typeof onComplete === 'function') {
2528
+ if(tilesToLoad.length > 0) {
2529
+ const currentZoom = map.getZoom();
2530
+ let zoomTileCount = 0;
2531
+ validGMTiles.forEach((tile) => {
2532
+ if(parseInt(tile.substring(0,tile.indexOf('|'))) == currentZoom ) {
2533
+ zoomTileCount++;
2534
+ }
2535
+ })
2536
+ if(tilesToLoad.length == zoomTileCount) {
2537
+ eventHandlers["OverlayTilesLoaded"]({
2538
+ type: 'SUCCESS',
2539
+ message: 'NDVI overlay completed',
2540
+ code: 200,
2541
+ data: tilesToLoad[0]
2542
+ });
2543
+ } else {
2544
+ eventHandlers["OverlayTilesLoaded"]({
2545
+ type: 'ERROR',
2546
+ message: 'Not all tiles loaded',
2547
+ code: 400,
2548
+ data: null
2549
+ });
2550
+ }
2551
+ } else {
2552
+ eventHandlers["OverlayTilesLoaded"]({
2553
+ type: 'ERROR',
2554
+ message: 'No tiles loaded',
2555
+ code: 400,
2556
+ data: null
2557
+ });
2558
+ }
2559
+ //}
2560
+
2561
+ tilesToLoad = [];
2562
+
2563
+ });
2564
+
2565
+ map.overlayMapTypes.push(vdiMapType);
2566
+ });
2567
+ mapListeners.push(zoomOnAddOverlayChangedListener);
2568
+
2569
+ map.setZoom(13);
2570
+
2571
+ } else {
2572
+ tilesToLoad = [];
2573
+
2574
+ var vdiMapType = new google.maps.ImageMapType({
2575
+ getTileUrl: function (coord, zoom) {
2576
+ if(vgmTiles.indexOf(zoom+'|'+coord.x+'|'+coord.y) > -1) {
2577
+ const booleanFullView = fullView ? 'true' : 'false';
2578
+ console.log([ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join(''));
2579
+ tilesToLoad.push({eosLocationCropperRefId: eosLocationCropperRefId, eosViewId: eosViewId, z: zoom});
2580
+ return [ndviTileURL.replace(/{l}/,eosLocationCropperRefId).replace(/{v}/,eosViewId).replace(/{p}/,paletteId).replace(/{f}/,booleanFullView).replace(/{z}/,zoom).replace(/{x}/,coord.x).replace(/{y}/,coord.y)].join('');
2581
+ }
2582
+ },
2583
+ tileSize: new google.maps.Size(256, 256),
2584
+ minZoom: 13,
2585
+ maxZoom: 17
2586
+ });
2587
+
2588
+ vdiMapType.addListener("tilesloaded", function() {
2589
+ if(spinnerSet) {
2590
+
2591
+ fmarkers.forEach(function(l,index) {
2592
+ l.setMap(null);
2593
+ fmarkers.splice(index, 1);
2594
+ spinnerSet = false;
2595
+ });
2596
+ }
2597
+
2598
+ var fullView = false;
2599
+ if(tilesToLoad.length > 0) {
2600
+ if(tilesToLoad[0].fullView == 1) {
2601
+ fullView = true;
2602
+ }
2603
+ }
2604
+
2605
+ if(tilesToLoad.length > 0) {
2606
+ const currentZoom = map.getZoom();
2607
+ let zoomTileCount = 0;
2608
+ validGMTiles.forEach((tile) => {
2609
+ if(parseInt(tile.substring(0,tile.indexOf('|'))) == currentZoom ) {
2610
+ zoomTileCount++;
2611
+ }
2612
+ })
2613
+ if(tilesToLoad.length == zoomTileCount) {
2614
+ eventHandlers["OverlayTilesLoaded"]({
2615
+ type: 'SUCCESS',
2616
+ message: 'NDVI overlay completed',
2617
+ code: 200,
2618
+ data: tilesToLoad[0]
2619
+ });
2620
+ } else {
2621
+ eventHandlers["OverlayTilesLoaded"]({
2622
+ type: 'ERROR',
2623
+ message: 'Not all tiles loaded',
2624
+ code: 400,
2625
+ data: null
2626
+ });
2627
+ }
2628
+ } else {
2629
+ eventHandlers["OverlayTilesLoaded"]({
2630
+ type: 'ERROR',
2631
+ message: 'No tiles loaded',
2632
+ code: 400,
2633
+ data: null
2634
+ });
2635
+ }
2636
+
2637
+ tilesToLoad = [];
2638
+
2639
+ });
2640
+
2641
+ map.overlayMapTypes.push(vdiMapType);
2642
+ }
2643
+ }
2644
+
2645
+ _this.NDVI_RemoveOverlay = function () {
2646
+ map.overlayMapTypes.clear();
2647
+ }
2648
+
2649
+
2650
+ _this.NDVI_DrawLocation = function (locationJson, offsetX, offsetY, vMapWidth, showTooltip) {
2651
+ var locationParsed = locationJson;
2652
+ var location = locationParsed[0];
2653
+ var polygon = null;
2654
+ var mapPanned = false;
2655
+
2656
+ if (location && location.Poly && location.Poly.length > 0 && location.Id > 0) {
2657
+ var paths = [];
2658
+ var polyBounds = new google.maps.LatLngBounds();
2659
+
2660
+
2661
+ location.Poly.forEach(function (poly, pIndex) {
2662
+ var path = [];
2663
+
2664
+ poly.forEach(function (v) {
2665
+ path.push(new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])));
2666
+ if(pIndex == 0) {
2667
+ polyBounds.extend(new google.maps.LatLng(parseFloat(v[1]), parseFloat(v[0])));
2668
+ }
2669
+ });
2670
+ paths.push(path);
2671
+ });
2672
+
2673
+ polygon = new google.maps.Polygon({
2674
+ map: map,
2675
+ paths: paths,
2676
+ fillColor: 'transparent'
2677
+
2678
+ });
2679
+
2680
+ var boundsChangedListener = google.maps.event.addListenerOnce(map, 'bounds_changed', function () {
2681
+ if(!mapPanned) {
2682
+
2683
+ var psw = map.getProjection().fromLatLngToPoint(polyBounds.getSouthWest());
2684
+ var pne = map.getProjection().fromLatLngToPoint(polyBounds.getNorthEast());
2685
+
2686
+ var zoom = map.getZoom();
2687
+ var scale = 1 << zoom;
2688
+
2689
+ if((pne.x - psw.x)*scale >= vMapWidth) {
2690
+ map.setZoom(zoom-1);
2691
+ }
2692
+
2693
+ if (map.getZoom() > 16) {
2694
+ map.setZoom(16);
2695
+ }
2696
+
2697
+ offsetCenter(polyBounds.getCenter(), offsetX, offsetY);
2698
+ mapPanned = !mapPanned;
2699
+ }
2700
+ });
2701
+ mapListeners.push(boundsChangedListener);
2702
+
2703
+ map.fitBounds(polyBounds);
2704
+
2705
+ if(showTooltip) {
2706
+
2707
+ var polygonMouseoverListener = google.maps.event.addListener(polygon, "mouseover", function(event) {
2708
+ injectTooltip(event, polygon.content);
2709
+ });
2710
+
2711
+ var polygonMousemoveListener = google.maps.event.addListener(polygon, 'mousemove', function(event) {
2712
+ moveTooltip(event);
2713
+ });
2714
+
2715
+ var polygonMouseoutListener = google.maps.event.addListener(polygon, 'mouseout', function(event) {
2716
+ deleteTooltip(event);
2717
+ });
2718
+
2719
+ polygonListeners.push(polygonMouseoverListener);
2720
+ polygonListeners.push(polygonMousemoveListener);
2721
+ polygonListeners.push(polygonMouseoutListener);
2722
+
2723
+ }
2724
+
2725
+ fpolies.push(polygon);
2726
+ }
2727
+
2728
+ if (map.getZoom() >= 13) {
2729
+ polyLabels.forEach(function (pl) {
2730
+ pl.setMap(map);
2731
+ });
2732
+ } else {
2733
+ polyLabels.forEach(function (pl) {
2734
+ pl.setMap(null);
2735
+ });
2736
+ }
2737
+
2738
+ var zoomChangedListener = google.maps.event.addListener(map, 'zoom_changed', function () {
2739
+
2740
+ if (map.getZoom() >= 13) {
2741
+ polyLabels.forEach(function (pl, index) {
2742
+ pl.setMap(map);
2743
+ });
2744
+ } else {
2745
+ polyLabels.forEach(function (pl, index) {
2746
+ pl.setMap(null);
2747
+ });
2748
+ }
2749
+ });
2750
+ mapListeners.push(zoomChangedListener);
2751
+ }
2752
+ }
2753
+ }