@aggdirect/coolmap-services 1.4.9 → 4.0.1
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.
- package/README.md +43 -18
- package/fesm2022/aggdirect-coolmap-services.mjs +851 -646
- package/fesm2022/aggdirect-coolmap-services.mjs.map +1 -1
- package/index.d.ts +212 -5
- package/package.json +13 -26
- package/esm2022/aggdirect-coolmap-services.mjs +0 -5
- package/esm2022/lib/service/coolmap.service.mjs +0 -637
- package/esm2022/lib/service/data-model.mjs +0 -92
- package/esm2022/lib/service/utils.service.mjs +0 -400
- package/esm2022/public-api.mjs +0 -7
- package/lib/service/coolmap.service.d.ts +0 -47
- package/lib/service/data-model.d.ts +0 -94
- package/lib/service/utils.service.d.ts +0 -78
- package/public-api.d.ts +0 -3
|
@@ -1,123 +1,40 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable,
|
|
3
|
-
import * as mapboxgl from 'mapbox-gl';
|
|
4
|
-
import * as turf from '@turf/turf';
|
|
2
|
+
import { Component, InjectionToken, inject, NgZone, Injectable, signal } from '@angular/core';
|
|
5
3
|
import { BehaviorSubject } from 'rxjs';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import * as i2 from '@angular/material/snack-bar';
|
|
10
|
-
import * as i2$1 from '@angular/platform-browser';
|
|
4
|
+
import mapboxgl from 'mapbox-gl';
|
|
5
|
+
import * as turf from '@turf/turf';
|
|
6
|
+
import { HttpClient } from '@angular/common/http';
|
|
11
7
|
|
|
12
|
-
class
|
|
13
|
-
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
delivery_lat;
|
|
20
|
-
delivery_location;
|
|
21
|
-
delivery_lon;
|
|
22
|
-
driver_list;
|
|
23
|
-
material;
|
|
24
|
-
order_number;
|
|
25
|
-
pickup_lat;
|
|
26
|
-
pickup_location;
|
|
27
|
-
pickup_lon;
|
|
28
|
-
project;
|
|
29
|
-
total_count;
|
|
30
|
-
unit;
|
|
31
|
-
values;
|
|
32
|
-
job_id;
|
|
33
|
-
isSelected;
|
|
34
|
-
date;
|
|
35
|
-
// Add Route
|
|
36
|
-
created_at;
|
|
37
|
-
created_by_name;
|
|
38
|
-
customer_id;
|
|
39
|
-
delivery_lat_lng;
|
|
40
|
-
estimated_distance;
|
|
41
|
-
estimated_time;
|
|
42
|
-
materials_id;
|
|
43
|
-
path;
|
|
44
|
-
pickup_lat_lng;
|
|
45
|
-
route_id;
|
|
46
|
-
route_name;
|
|
47
|
-
unit_id;
|
|
48
|
-
note;
|
|
49
|
-
materialLabel;
|
|
50
|
-
isActive;
|
|
51
|
-
prevent;
|
|
52
|
-
is_system_pickup;
|
|
53
|
-
is_system_delivery;
|
|
54
|
-
}
|
|
55
|
-
const EstinationData = ['estimated_distance', 'estimated_time'];
|
|
56
|
-
var EstinationEnum;
|
|
57
|
-
(function (EstinationEnum) {
|
|
58
|
-
EstinationEnum["estimated_distance"] = "miles";
|
|
59
|
-
EstinationEnum["estimated_time"] = "time";
|
|
60
|
-
})(EstinationEnum || (EstinationEnum = {}));
|
|
61
|
-
const JobCodeOverviewData = ['order_number', 'customer_name', 'project', 'unit', 'material', 'customer_contact', 'delivery_contact', 'pickup_location', 'delivery_location'];
|
|
62
|
-
var JobCodeOverviewEnum;
|
|
63
|
-
(function (JobCodeOverviewEnum) {
|
|
64
|
-
JobCodeOverviewEnum["material"] = "Material";
|
|
65
|
-
JobCodeOverviewEnum["order_number"] = "Job Code";
|
|
66
|
-
JobCodeOverviewEnum["customer_name"] = "Customer";
|
|
67
|
-
JobCodeOverviewEnum["customer_contact"] = "Customer Contact";
|
|
68
|
-
JobCodeOverviewEnum["delivery_contact"] = "Delivery Contact";
|
|
69
|
-
JobCodeOverviewEnum["project"] = "Project Name";
|
|
70
|
-
JobCodeOverviewEnum["unit"] = "Job Type";
|
|
71
|
-
JobCodeOverviewEnum["pickup_location"] = "Pickup";
|
|
72
|
-
JobCodeOverviewEnum["delivery_location"] = "Delivery";
|
|
73
|
-
})(JobCodeOverviewEnum || (JobCodeOverviewEnum = {}));
|
|
74
|
-
const DriversmsCardKey = ['order_number', 'date', 'values', 'material', 'unit', 'pickup_location', 'delivery_location'];
|
|
75
|
-
var DriverSmsCardEnum;
|
|
76
|
-
(function (DriverSmsCardEnum) {
|
|
77
|
-
DriverSmsCardEnum["order_number"] = "Jobcode";
|
|
78
|
-
DriverSmsCardEnum["date"] = "Date";
|
|
79
|
-
DriverSmsCardEnum["values"] = "Total tasks";
|
|
80
|
-
DriverSmsCardEnum["material"] = "Material";
|
|
81
|
-
DriverSmsCardEnum["unit"] = "Unit";
|
|
82
|
-
DriverSmsCardEnum["pickup_location"] = "Pickup Address";
|
|
83
|
-
DriverSmsCardEnum["delivery_location"] = "Delivery Address";
|
|
84
|
-
})(DriverSmsCardEnum || (DriverSmsCardEnum = {}));
|
|
85
|
-
class PopupData {
|
|
86
|
-
coordinate;
|
|
87
|
-
pickup;
|
|
88
|
-
jobCode;
|
|
89
|
-
customer;
|
|
90
|
-
drop;
|
|
91
|
-
routeType;
|
|
92
|
-
title;
|
|
93
|
-
material;
|
|
94
|
-
type;
|
|
8
|
+
class CoolmapServices {
|
|
9
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapServices, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: CoolmapServices, isStandalone: true, selector: "lib-coolmap-services", ngImport: i0, template: `
|
|
11
|
+
<p>
|
|
12
|
+
coolmap-services works!
|
|
13
|
+
</p>
|
|
14
|
+
`, isInline: true, styles: [""] });
|
|
95
15
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
16
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapServices, decorators: [{
|
|
17
|
+
type: Component,
|
|
18
|
+
args: [{ selector: 'lib-coolmap-services', imports: [], template: `
|
|
19
|
+
<p>
|
|
20
|
+
coolmap-services works!
|
|
21
|
+
</p>
|
|
22
|
+
` }]
|
|
23
|
+
}] });
|
|
24
|
+
|
|
25
|
+
const COOLMAP_CONFIG = new InjectionToken('COOLMAP_CONFIG');
|
|
26
|
+
function provideCoolmapConfig(config) {
|
|
27
|
+
return {
|
|
28
|
+
provide: COOLMAP_CONFIG,
|
|
29
|
+
useValue: config
|
|
30
|
+
};
|
|
102
31
|
}
|
|
103
32
|
|
|
104
33
|
class UtilsService {
|
|
105
|
-
http;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
analyticsRESTURL = '';
|
|
110
|
-
RESTURLPrefix = '';
|
|
111
|
-
pickupOptions = [];
|
|
112
|
-
destOptions = [];
|
|
113
|
-
ownerOptions = [];
|
|
114
|
-
customerOptions = [];
|
|
115
|
-
unitOptions = [];
|
|
116
|
-
materialOptions = [];
|
|
117
|
-
jcodeOptions = [];
|
|
118
|
-
driverOption = [];
|
|
119
|
-
truckingCompanayOption = [];
|
|
120
|
-
routeNameOptions = [];
|
|
34
|
+
http = inject(HttpClient);
|
|
35
|
+
config = inject(COOLMAP_CONFIG);
|
|
36
|
+
ngZone = inject(NgZone);
|
|
37
|
+
// BehaviorSubjects for state (converting to simple Signals later where practical)
|
|
121
38
|
preventnavChange = new BehaviorSubject(false);
|
|
122
39
|
navChangeObserve = this.preventnavChange.asObservable();
|
|
123
40
|
clearViewRouteforJobCode = new BehaviorSubject(false);
|
|
@@ -134,97 +51,96 @@ class UtilsService {
|
|
|
134
51
|
materialsListForCustomer;
|
|
135
52
|
customersList;
|
|
136
53
|
locationList;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
54
|
+
// Options filtering properties
|
|
55
|
+
pickupOptions = [];
|
|
56
|
+
destOptions = [];
|
|
57
|
+
ownerOptions = [];
|
|
58
|
+
customerOptions = [];
|
|
59
|
+
unitOptions = [];
|
|
60
|
+
materialOptions = [];
|
|
61
|
+
jcodeOptions = [];
|
|
62
|
+
driverOption = [];
|
|
63
|
+
truckingCompanayOption = [];
|
|
64
|
+
routeNameOptions = [];
|
|
146
65
|
getDateFormat(strVal, seprater) {
|
|
147
66
|
seprater = seprater ? seprater : '-';
|
|
148
67
|
const mydate = strVal;
|
|
149
|
-
|
|
68
|
+
if (!mydate)
|
|
69
|
+
return '';
|
|
70
|
+
const month = String(mydate.getMonth() + 1).padStart(2, '0');
|
|
71
|
+
const day = String(mydate.getDate()).padStart(2, '0');
|
|
72
|
+
return (mydate.getFullYear() +
|
|
150
73
|
seprater +
|
|
151
|
-
|
|
74
|
+
month +
|
|
152
75
|
seprater +
|
|
153
|
-
|
|
76
|
+
day);
|
|
154
77
|
}
|
|
155
78
|
getData(path) {
|
|
156
|
-
return this.http.get(`${this.analyticsRESTURL}${this.config.repository}/${path}`);
|
|
79
|
+
return this.http.get(`${this.config.analyticsRESTURL}${this.config.repository}/${path}`);
|
|
157
80
|
}
|
|
158
81
|
getRestData(path) {
|
|
159
|
-
return this.http.get(`${this.RESTURLPrefix}${path}`);
|
|
82
|
+
return this.http.get(`${this.config.RESTURLPrefix}${path}`);
|
|
160
83
|
}
|
|
161
84
|
postdata(path, data) {
|
|
162
|
-
return this.http.post(`${this.analyticsRESTURL}${this.config.repository}/${path}`, data);
|
|
85
|
+
return this.http.post(`${this.config.analyticsRESTURL}${this.config.repository}/${path}`, data);
|
|
163
86
|
}
|
|
164
87
|
postDataWithRestUrl(path, data) {
|
|
165
|
-
return this.http.post(`${this.RESTURLPrefix}${path}`, data);
|
|
166
|
-
}
|
|
167
|
-
autocomplete(searchElementRef, type) {
|
|
168
|
-
return new Promise((resolve, reject) => {
|
|
169
|
-
const autocomplete = new google.maps.places.Autocomplete(searchElementRef.nativeElement, {
|
|
170
|
-
types: ['address']
|
|
171
|
-
});
|
|
172
|
-
google.maps.event.addListener(autocomplete, 'place_changed', () => {
|
|
173
|
-
this.ngZone.run(() => {
|
|
174
|
-
const place = autocomplete.getPlace();
|
|
175
|
-
resolve({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng(), formatted_address: place['formatted_address'] });
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
});
|
|
88
|
+
return this.http.post(`${this.config.RESTURLPrefix}${path}`, data);
|
|
179
89
|
}
|
|
90
|
+
// Instead of MatSnackBar, we just use a generic console/alert fallback for now.
|
|
180
91
|
openSnackBar(message, className) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
92
|
+
}
|
|
93
|
+
clearOptions() {
|
|
94
|
+
this.pickupOptions = [];
|
|
95
|
+
this.destOptions = [];
|
|
96
|
+
this.ownerOptions = [];
|
|
97
|
+
this.customerOptions = [];
|
|
98
|
+
this.unitOptions = [];
|
|
99
|
+
this.materialOptions = [];
|
|
100
|
+
this.jcodeOptions = [];
|
|
101
|
+
this.routeNameOptions = [];
|
|
187
102
|
}
|
|
188
103
|
makeOptions(item) {
|
|
104
|
+
// Porting V1 makeOptions safely
|
|
189
105
|
if (item.order_number) {
|
|
190
|
-
this.jcodeOptions.findIndex((elem) => elem.job_id === item.job_id) === -1
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
: null;
|
|
106
|
+
if (this.jcodeOptions.findIndex((elem) => elem.job_id === item.job_id) === -1) {
|
|
107
|
+
this.jcodeOptions.push({ job_code: item.order_number, job_id: item.job_id });
|
|
108
|
+
}
|
|
109
|
+
// Assuming tasks structure if Mapbox Route logic was merged, else driver_list from V1
|
|
110
|
+
const driver_list = item.driver_list || [];
|
|
111
|
+
if (driver_list.length > 0) {
|
|
112
|
+
driver_list.forEach((driver) => {
|
|
113
|
+
if (this.driverOption.findIndex((elem) => elem === driver.driver_name) === -1) {
|
|
114
|
+
this.driverOption.push(driver.driver_name);
|
|
115
|
+
}
|
|
116
|
+
if (this.truckingCompanayOption.findIndex((elem) => elem === driver.trucking_company) === -1) {
|
|
117
|
+
this.truckingCompanayOption.push(driver.trucking_company);
|
|
118
|
+
}
|
|
204
119
|
});
|
|
205
120
|
}
|
|
206
121
|
}
|
|
207
|
-
this.pickupOptions.findIndex((elem) => elem === item.pickup_location) === -1
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
122
|
+
if (item.pickup_location && this.pickupOptions.findIndex((elem) => elem === item.pickup_location) === -1)
|
|
123
|
+
this.pickupOptions.push(item.pickup_location);
|
|
124
|
+
if (item.delivery_location && this.destOptions.findIndex((elem) => elem === item.delivery_location) === -1)
|
|
125
|
+
this.destOptions.push(item.delivery_location);
|
|
126
|
+
if (item.customer_name && this.customerOptions.findIndex((customer) => customer === item.customer_name) === -1)
|
|
127
|
+
this.customerOptions.push(item.customer_name);
|
|
128
|
+
if (item.unit && this.unitOptions.findIndex((elem) => elem === item.unit) === -1)
|
|
129
|
+
this.unitOptions.push(item.unit);
|
|
130
|
+
if (item.material && this.materialOptions.findIndex((elem) => elem === item.material) === -1)
|
|
131
|
+
this.materialOptions.push(item.material);
|
|
132
|
+
if (item.route_name && this.routeNameOptions.findIndex((elem) => elem === item.route_name) === -1)
|
|
133
|
+
this.routeNameOptions.push(item.route_name);
|
|
134
|
+
}
|
|
135
|
+
setdictValue(key, value) {
|
|
136
|
+
this.dict.set(key, value);
|
|
137
|
+
}
|
|
138
|
+
getdictValue(key) {
|
|
139
|
+
const val = this.dict.get(key);
|
|
140
|
+
return val ? JSON.parse(val) : null;
|
|
141
|
+
}
|
|
142
|
+
removedictValue(key) {
|
|
143
|
+
this.dict.delete(key);
|
|
228
144
|
}
|
|
229
145
|
filter(value, filters) {
|
|
230
146
|
if (typeof value !== 'string') {
|
|
@@ -235,24 +151,24 @@ class UtilsService {
|
|
|
235
151
|
return [];
|
|
236
152
|
}
|
|
237
153
|
const searchResults = [];
|
|
238
|
-
this.unitOptions.
|
|
154
|
+
this.unitOptions.forEach((unit) => {
|
|
239
155
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
240
156
|
searchResults.push({ type: 'unit', label: unit, value: unit });
|
|
241
157
|
}
|
|
242
158
|
});
|
|
243
|
-
this.customerOptions.
|
|
159
|
+
this.customerOptions.forEach((unit) => {
|
|
244
160
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
245
161
|
searchResults.push({ type: 'customer', label: unit, value: unit });
|
|
246
162
|
}
|
|
247
163
|
});
|
|
248
|
-
if (this.materialOptions.length) {
|
|
249
|
-
this.materialOptions.
|
|
164
|
+
if (this.materialOptions && this.materialOptions.length) {
|
|
165
|
+
this.materialOptions.forEach((unit) => {
|
|
250
166
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
251
167
|
searchResults.push({ type: 'material', label: unit, value: unit });
|
|
252
168
|
}
|
|
253
169
|
});
|
|
254
170
|
}
|
|
255
|
-
this.pickupOptions.
|
|
171
|
+
this.pickupOptions.forEach((unit) => {
|
|
256
172
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
257
173
|
searchResults.push({
|
|
258
174
|
type: 'pickup location',
|
|
@@ -261,7 +177,7 @@ class UtilsService {
|
|
|
261
177
|
});
|
|
262
178
|
}
|
|
263
179
|
});
|
|
264
|
-
this.destOptions.
|
|
180
|
+
this.destOptions.forEach((unit) => {
|
|
265
181
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
266
182
|
searchResults.push({
|
|
267
183
|
type: 'destination location',
|
|
@@ -270,7 +186,7 @@ class UtilsService {
|
|
|
270
186
|
});
|
|
271
187
|
}
|
|
272
188
|
});
|
|
273
|
-
this.jcodeOptions.
|
|
189
|
+
this.jcodeOptions.forEach((unit) => {
|
|
274
190
|
if (unit.job_code.toLowerCase().includes(filterValue)) {
|
|
275
191
|
searchResults.push({
|
|
276
192
|
type: 'job',
|
|
@@ -279,12 +195,12 @@ class UtilsService {
|
|
|
279
195
|
});
|
|
280
196
|
}
|
|
281
197
|
});
|
|
282
|
-
this.driverOption.
|
|
198
|
+
this.driverOption.forEach((unit) => {
|
|
283
199
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
284
200
|
searchResults.push({ type: 'Driver', label: unit, value: unit });
|
|
285
201
|
}
|
|
286
202
|
});
|
|
287
|
-
this.truckingCompanayOption.
|
|
203
|
+
this.truckingCompanayOption.forEach((unit) => {
|
|
288
204
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
289
205
|
searchResults.push({
|
|
290
206
|
type: 'Trucking Company',
|
|
@@ -293,20 +209,19 @@ class UtilsService {
|
|
|
293
209
|
});
|
|
294
210
|
}
|
|
295
211
|
});
|
|
296
|
-
this.routeNameOptions.
|
|
212
|
+
this.routeNameOptions.forEach((unit) => {
|
|
297
213
|
if (unit.toLowerCase().includes(filterValue)) {
|
|
298
214
|
searchResults.push({ type: 'Route name', label: unit, value: unit });
|
|
299
215
|
}
|
|
300
216
|
});
|
|
217
|
+
// Filter out options that are already selected in the filters array
|
|
301
218
|
const searchDict = {};
|
|
302
|
-
filters.
|
|
219
|
+
filters.forEach((filter) => {
|
|
303
220
|
searchDict[filter['name'] + filter['type']] = filter;
|
|
304
221
|
});
|
|
305
222
|
const furtherFilter = [];
|
|
306
|
-
searchResults.
|
|
307
|
-
if (search['label'] + search['type'] in searchDict) {
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
223
|
+
searchResults.forEach((search) => {
|
|
224
|
+
if (!(search['label'] + search['type'] in searchDict)) {
|
|
310
225
|
furtherFilter.push(search);
|
|
311
226
|
}
|
|
312
227
|
});
|
|
@@ -317,15 +232,13 @@ class UtilsService {
|
|
|
317
232
|
const result_list_boolean = [];
|
|
318
233
|
if (filterval.length > 0) {
|
|
319
234
|
if (filterval[0]['type'] === 'unit') {
|
|
320
|
-
result_list_boolean.push(filterval[0]['name'] ===
|
|
321
|
-
element[filterval[0]['type']]);
|
|
235
|
+
result_list_boolean.push(filterval[0]['name'] === element['unit']);
|
|
322
236
|
}
|
|
323
237
|
if (filterval[0]['type'] === 'customer') {
|
|
324
238
|
result_list_boolean.push(filterval[0]['name'] === element['customer_name']);
|
|
325
239
|
}
|
|
326
240
|
if (filterval[0]['type'] === 'material') {
|
|
327
|
-
result_list_boolean.push(filterval[0]['name'] ===
|
|
328
|
-
element[filterval[0]['type']]);
|
|
241
|
+
result_list_boolean.push(filterval[0]['name'] === element['material']);
|
|
329
242
|
}
|
|
330
243
|
if (filterval[0]['type'] === 'pickup location') {
|
|
331
244
|
result_list_boolean.push(filterval[0]['name'] === element['pickup_location']);
|
|
@@ -340,14 +253,16 @@ class UtilsService {
|
|
|
340
253
|
result_list_boolean.push(filterval[0]['name'] === element['route_name']);
|
|
341
254
|
}
|
|
342
255
|
if (filterval[0]['type'] === 'Driver') {
|
|
343
|
-
const
|
|
256
|
+
const driverList = element.driver_list || [];
|
|
257
|
+
const index = driverList.findIndex((ele) => {
|
|
344
258
|
return filterval[0]['name'] === ele['driver_name'];
|
|
345
259
|
});
|
|
346
260
|
if (index !== -1)
|
|
347
261
|
result_list_boolean.push(true);
|
|
348
262
|
}
|
|
349
263
|
if (filterval[0]['type'] === 'Trucking Company') {
|
|
350
|
-
const
|
|
264
|
+
const driverList = element.driver_list || [];
|
|
265
|
+
const index = driverList.findIndex((ele) => {
|
|
351
266
|
return filterval[0]['name'] === ele['trucking_company'];
|
|
352
267
|
});
|
|
353
268
|
if (index !== -1)
|
|
@@ -360,32 +275,8 @@ class UtilsService {
|
|
|
360
275
|
return false;
|
|
361
276
|
});
|
|
362
277
|
}
|
|
363
|
-
clearOptions() {
|
|
364
|
-
this.pickupOptions = [];
|
|
365
|
-
this.destOptions = [];
|
|
366
|
-
this.ownerOptions = [];
|
|
367
|
-
this.customerOptions = [];
|
|
368
|
-
this.unitOptions = [];
|
|
369
|
-
this.materialOptions = [];
|
|
370
|
-
this.jcodeOptions = [];
|
|
371
|
-
this.routeNameOptions = [];
|
|
372
|
-
}
|
|
373
|
-
setdictValue(key, value) {
|
|
374
|
-
this.dict.set(key, value);
|
|
375
|
-
}
|
|
376
|
-
getdictValue(key) {
|
|
377
|
-
return JSON.parse(this.dict.get(key));
|
|
378
|
-
}
|
|
379
|
-
removedictValue(key) {
|
|
380
|
-
this.dict.delete(key);
|
|
381
|
-
}
|
|
382
|
-
conveySearchIcon(value) {
|
|
383
|
-
if (value && typeof value !== 'object')
|
|
384
|
-
return true;
|
|
385
|
-
return false;
|
|
386
|
-
}
|
|
387
278
|
fetchUnitsList() {
|
|
388
|
-
return new Promise((resolve
|
|
279
|
+
return new Promise((resolve) => {
|
|
389
280
|
if (!this.unitsList) {
|
|
390
281
|
this.getData('unit/list/view').subscribe((res) => {
|
|
391
282
|
if (res) {
|
|
@@ -399,21 +290,8 @@ class UtilsService {
|
|
|
399
290
|
}
|
|
400
291
|
});
|
|
401
292
|
}
|
|
402
|
-
fetchMaterialsList() {
|
|
403
|
-
return new Promise((resolve, reject) => {
|
|
404
|
-
if (!this.materialsList) {
|
|
405
|
-
this.getData('material/list/view').subscribe((res) => {
|
|
406
|
-
this.materialsList = this.filtermaterialList(res.data);
|
|
407
|
-
resolve(this.materialsList);
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
resolve(this.materialsList);
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
293
|
fetchMaterialsListForCustomer() {
|
|
416
|
-
return new Promise((resolve
|
|
294
|
+
return new Promise((resolve) => {
|
|
417
295
|
if (!this.materialsListForCustomer) {
|
|
418
296
|
this.getData('material/list/view').subscribe((res) => {
|
|
419
297
|
this.materialsListForCustomer = this.filtermaterialList(res.data);
|
|
@@ -427,9 +305,9 @@ class UtilsService {
|
|
|
427
305
|
}
|
|
428
306
|
filtermaterialList(list) {
|
|
429
307
|
let meterialList = [];
|
|
430
|
-
list.
|
|
431
|
-
if (item.sub.length > 0) {
|
|
432
|
-
item.sub.
|
|
308
|
+
list.forEach((item) => {
|
|
309
|
+
if (item.sub && item.sub.length > 0) {
|
|
310
|
+
item.sub.forEach((subItem) => {
|
|
433
311
|
if (subItem.add_to_marketplace) {
|
|
434
312
|
subItem.material = item.material;
|
|
435
313
|
subItem.material_id = item.material_id;
|
|
@@ -443,7 +321,7 @@ class UtilsService {
|
|
|
443
321
|
return meterialList;
|
|
444
322
|
}
|
|
445
323
|
fetchCustomersList() {
|
|
446
|
-
return new Promise((resolve
|
|
324
|
+
return new Promise((resolve) => {
|
|
447
325
|
if (!this.customersList) {
|
|
448
326
|
this.getData('company/list/view').subscribe((res) => {
|
|
449
327
|
if (res) {
|
|
@@ -459,99 +337,129 @@ class UtilsService {
|
|
|
459
337
|
}
|
|
460
338
|
fetchLocationlist() {
|
|
461
339
|
return new Promise((resolve, reject) => {
|
|
462
|
-
this.getRestData('locations/all').subscribe(
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
340
|
+
this.getRestData('locations/all').subscribe({
|
|
341
|
+
next: (res) => {
|
|
342
|
+
if (res) {
|
|
343
|
+
this.locationList = res.data.map((object) => {
|
|
344
|
+
object.formatted_address = `${object.name} | ${object.street} ${object.city}, ${object.state} ${object.zip}`;
|
|
345
|
+
return {
|
|
346
|
+
city: object.city,
|
|
347
|
+
lng: object.longitude,
|
|
348
|
+
location_id: object.location_id,
|
|
349
|
+
lat: object.latitude,
|
|
350
|
+
name: object.name,
|
|
351
|
+
state: object.state,
|
|
352
|
+
street: object.street,
|
|
353
|
+
zip: object.zip,
|
|
354
|
+
formatted_address: object.formatted_address
|
|
355
|
+
};
|
|
356
|
+
});
|
|
357
|
+
resolve(this.locationList);
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
error: (err) => {
|
|
361
|
+
console.error(err);
|
|
362
|
+
reject(err);
|
|
481
363
|
}
|
|
482
|
-
}, err => {
|
|
483
|
-
console.log(err);
|
|
484
364
|
});
|
|
485
365
|
});
|
|
486
366
|
}
|
|
487
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
488
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
367
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
368
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UtilsService, providedIn: 'root' });
|
|
489
369
|
}
|
|
490
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
370
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: UtilsService, decorators: [{
|
|
491
371
|
type: Injectable,
|
|
492
372
|
args: [{ providedIn: 'root' }]
|
|
493
|
-
}]
|
|
494
|
-
type: Inject,
|
|
495
|
-
args: ['memberData']
|
|
496
|
-
}] }, { type: i0.NgZone }] });
|
|
373
|
+
}] });
|
|
497
374
|
|
|
498
|
-
class
|
|
499
|
-
utils;
|
|
500
|
-
eventManager;
|
|
501
|
-
config;
|
|
375
|
+
class MapboxService {
|
|
502
376
|
map;
|
|
503
|
-
|
|
504
|
-
|
|
377
|
+
mapContainer = null;
|
|
378
|
+
markerOriginList = new Map();
|
|
379
|
+
markerDestinationList = new Map();
|
|
380
|
+
activeRoutesRegistry = new Map();
|
|
381
|
+
pathCache = new Map();
|
|
382
|
+
// Native 3D Simulation Engine
|
|
383
|
+
svgOverlay = null;
|
|
384
|
+
activeArcs = {};
|
|
505
385
|
initiatecoolmap = new BehaviorSubject(true);
|
|
506
386
|
reintiatecoolmap = this.initiatecoolmap.asObservable();
|
|
387
|
+
isMapReady = signal(false, ...(ngDevMode ? [{ debugName: "isMapReady" }] : []));
|
|
507
388
|
bounds = new mapboxgl.LngLatBounds();
|
|
508
389
|
originDestinationCordinates = [];
|
|
509
390
|
padding;
|
|
510
|
-
windowActualHeightWidth;
|
|
391
|
+
windowActualHeightWidth = { availHeight: 0 };
|
|
511
392
|
popup;
|
|
512
393
|
customTopForCustomer;
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
394
|
+
utils = inject(UtilsService);
|
|
395
|
+
config = inject(COOLMAP_CONFIG);
|
|
396
|
+
currentStyleIsDark = false;
|
|
397
|
+
constructor() {
|
|
517
398
|
this.customTopForCustomer = this.config.repository === 'customer' ? 65 : 0;
|
|
518
|
-
|
|
519
|
-
|
|
399
|
+
if (typeof window !== 'undefined') {
|
|
400
|
+
this.windowActualHeightWidth.availHeight = window.innerHeight > window.screen.availHeight ? window.innerHeight : window.screen.availHeight;
|
|
401
|
+
window.addEventListener('resize', this.onResize.bind(this));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
updateTheme(isDark) {
|
|
405
|
+
if (!this.map) {
|
|
406
|
+
this.currentStyleIsDark = isDark;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (this.currentStyleIsDark === isDark)
|
|
410
|
+
return;
|
|
411
|
+
this.currentStyleIsDark = isDark;
|
|
412
|
+
const style = isDark
|
|
413
|
+
? 'mapbox://styles/mapbox/dark-v11'
|
|
414
|
+
: 'mapbox://styles/mapbox/light-v11';
|
|
415
|
+
this.map.setStyle(style);
|
|
416
|
+
this.map.once('style.load', () => {
|
|
417
|
+
this.reAddLayers();
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
getRegistryKeys() {
|
|
421
|
+
return Array.from(this.activeRoutesRegistry.keys());
|
|
520
422
|
}
|
|
521
|
-
|
|
423
|
+
// Renamed to initializeMap to preserve the existing bindings in coolmap.component.ts
|
|
424
|
+
initializeMap(el, isDark = false) {
|
|
425
|
+
this.currentStyleIsDark = isDark;
|
|
522
426
|
return new Promise((resolve, reject) => {
|
|
427
|
+
this.mapContainer = el;
|
|
523
428
|
if (this.map)
|
|
524
429
|
this.map.remove();
|
|
430
|
+
const token = typeof window !== 'undefined' ? window.__env?.mapboxAccessToken || '' : '';
|
|
431
|
+
mapboxgl.accessToken = token;
|
|
525
432
|
this.map = new mapboxgl.Map({
|
|
526
|
-
accessToken: this.config.mapboxAccessToken,
|
|
527
433
|
container: el,
|
|
528
|
-
style:
|
|
434
|
+
style: isDark ? 'mapbox://styles/mapbox/dark-v11' : 'mapbox://styles/mapbox/light-v11',
|
|
529
435
|
center: [-77.036873, 38.907192],
|
|
530
436
|
zoom: 10,
|
|
531
437
|
bearing: 0,
|
|
532
438
|
pitch: 65,
|
|
533
439
|
interactive: true,
|
|
440
|
+
attributionControl: false
|
|
534
441
|
});
|
|
442
|
+
this.map.addControl(new mapboxgl.AttributionControl({ compact: true }), 'bottom-right');
|
|
443
|
+
this.map.addControl(new mapboxgl.NavigationControl({ showCompass: false }), 'top-right');
|
|
535
444
|
this.map.once('load', (res) => {
|
|
445
|
+
this.isMapReady.set(true);
|
|
536
446
|
resolve(res);
|
|
537
447
|
});
|
|
538
448
|
});
|
|
539
449
|
}
|
|
540
|
-
//
|
|
541
|
-
loadMapProperty(pinRouteGeojson, index, unit,
|
|
542
|
-
return new Promise((resolve
|
|
543
|
-
|
|
450
|
+
// Animated gradient path
|
|
451
|
+
loadMapProperty(pinRouteGeojson, index, unit, routeProps, bottom) {
|
|
452
|
+
return new Promise((resolve) => {
|
|
453
|
+
if (!this.map || !this.isMapReady())
|
|
454
|
+
return resolve(false);
|
|
455
|
+
const origin = pinRouteGeojson.features[0].geometry.coordinates[0];
|
|
544
456
|
const linecolor = unit === 'Ton' ? '#ff7272' : unit === 'Load' ? '#a3c52e' : '#ae23d1';
|
|
545
|
-
|
|
546
|
-
this.extendBound(pinRouteGeojson.features[0].geometry.coordinates, true).then((
|
|
457
|
+
const destination = pinRouteGeojson.features[0].geometry.coordinates[pinRouteGeojson.features[0].geometry.coordinates.length - 1];
|
|
458
|
+
this.extendBound(pinRouteGeojson.features[0].geometry.coordinates, true).then(() => {
|
|
547
459
|
const point = {
|
|
548
460
|
type: 'FeatureCollection',
|
|
549
461
|
features: [
|
|
550
|
-
{
|
|
551
|
-
type: 'Feature',
|
|
552
|
-
properties: {},
|
|
553
|
-
geometry: { type: 'Point', coordinates: origin },
|
|
554
|
-
},
|
|
462
|
+
{ type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: origin } },
|
|
555
463
|
],
|
|
556
464
|
};
|
|
557
465
|
const lineDistance = turf.length(pinRouteGeojson.features[0]);
|
|
@@ -583,21 +491,9 @@ class CoolmapService {
|
|
|
583
491
|
paint: {
|
|
584
492
|
'line-width': 2,
|
|
585
493
|
'line-gradient': [
|
|
586
|
-
'interpolate',
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
0,
|
|
590
|
-
unit === 'Ton'
|
|
591
|
-
? '#d7f7e4'
|
|
592
|
-
: unit === 'Load'
|
|
593
|
-
? '#c9d8f5'
|
|
594
|
-
: '#f5dcc1',
|
|
595
|
-
1,
|
|
596
|
-
unit === 'Ton'
|
|
597
|
-
? '#ff7272'
|
|
598
|
-
: unit === 'Load'
|
|
599
|
-
? '#a3c52e'
|
|
600
|
-
: '#ae23d1',
|
|
494
|
+
'interpolate', ['linear'], ['line-progress'],
|
|
495
|
+
0, unit === 'Ton' ? '#d7f7e4' : unit === 'Load' ? '#c9d8f5' : '#f5dcc1',
|
|
496
|
+
1, unit === 'Ton' ? '#ff7272' : unit === 'Load' ? '#a3c52e' : '#ae23d1',
|
|
601
497
|
],
|
|
602
498
|
},
|
|
603
499
|
layout: { 'line-cap': 'round', 'line-join': 'round' },
|
|
@@ -616,7 +512,8 @@ class CoolmapService {
|
|
|
616
512
|
destination,
|
|
617
513
|
lineDistance,
|
|
618
514
|
linecolor,
|
|
619
|
-
route,
|
|
515
|
+
route: routeProps,
|
|
516
|
+
routeType: 'addroute',
|
|
620
517
|
isViewRoute: true,
|
|
621
518
|
};
|
|
622
519
|
this.createMarker(dataSetForMap);
|
|
@@ -625,61 +522,218 @@ class CoolmapService {
|
|
|
625
522
|
this.map.setPaintProperty(`line${index}`, 'line-opacity', 1);
|
|
626
523
|
const datasetForPopup = {
|
|
627
524
|
coordinate: [e.lngLat.lng, e.lngLat.lat],
|
|
628
|
-
pickup:
|
|
629
|
-
drop:
|
|
630
|
-
routeType:
|
|
631
|
-
title:
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
? route.route_name
|
|
635
|
-
: '',
|
|
636
|
-
material: route.material ? route.material : '',
|
|
637
|
-
type: route.unit ? route.unit : '',
|
|
525
|
+
pickup: routeProps?.pickup_location || '',
|
|
526
|
+
drop: routeProps?.delivery_location || '',
|
|
527
|
+
routeType: routeProps?.project ? 'Project' : 'Route',
|
|
528
|
+
title: routeProps?.project ? routeProps.project : routeProps?.route_name || '',
|
|
529
|
+
material: routeProps?.material || '',
|
|
530
|
+
type: routeProps?.unit || '',
|
|
638
531
|
};
|
|
639
532
|
if (this.popup)
|
|
640
533
|
this.popup.remove();
|
|
641
534
|
this.createPopup(datasetForPopup);
|
|
642
535
|
});
|
|
643
|
-
this.map.on('mouseleave', `line${index}`, (
|
|
536
|
+
this.map.on('mouseleave', `line${index}`, () => {
|
|
644
537
|
this.map.setPaintProperty(`line${index}`, 'line-width', 2);
|
|
645
|
-
if (this.popup)
|
|
538
|
+
if (this.popup)
|
|
646
539
|
this.popup.remove();
|
|
647
|
-
}
|
|
648
540
|
});
|
|
649
541
|
}
|
|
650
542
|
});
|
|
651
|
-
this.map.once('idle', (
|
|
543
|
+
this.map.once('idle', () => {
|
|
652
544
|
resolve(true);
|
|
653
545
|
});
|
|
654
546
|
});
|
|
655
547
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
548
|
+
createMarker(routeDetails) {
|
|
549
|
+
if (!this.map || !routeDetails.origin[0] || !routeDetails.origin[1] || !routeDetails.destination[0] || !routeDetails.destination[1])
|
|
550
|
+
return;
|
|
551
|
+
const popup = new mapboxgl.Popup({ closeButton: false }).setHTML('<b>Pickup: </b>' + (routeDetails.route?.pickup_location || ''));
|
|
552
|
+
const popupForDestination = new mapboxgl.Popup({ closeButton: false }).setHTML('<b>Delivery: </b>' + (routeDetails.route?.delivery_location || ''));
|
|
553
|
+
// Origin Marker (Pickup)
|
|
554
|
+
const el = document.createElement('div');
|
|
555
|
+
el.className = 'cursor-pointer active:scale-95 transition-transform duration-200 drop-shadow-lg';
|
|
556
|
+
const pickupLabel = 'P';
|
|
557
|
+
el.innerHTML = `
|
|
558
|
+
<svg width="30" height="38" viewBox="0 0 30 38" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
559
|
+
<path d="M15 0C6.71573 0 0 6.71573 0 15C0 26.25 15 38 15 38C15 38 30 26.25 30 15C30 6.71573 23.2843 0 15 0Z" fill="${routeDetails.linecolor}"/>
|
|
560
|
+
<circle cx="15" cy="15" r="9" fill="white"/>
|
|
561
|
+
<text x="15" y="19" text-anchor="middle" fill="black" style="font-family: Inter, sans-serif; font-size: 13px; font-weight: 800;">${pickupLabel}</text>
|
|
562
|
+
</svg>
|
|
563
|
+
`;
|
|
564
|
+
const originMarker = new mapboxgl.Marker({ element: el, anchor: 'bottom' })
|
|
565
|
+
.setPopup(popup)
|
|
566
|
+
.setLngLat(routeDetails.origin)
|
|
567
|
+
.addTo(this.map);
|
|
568
|
+
originMarker.getElement().addEventListener('mouseenter', () => originMarker.togglePopup());
|
|
569
|
+
originMarker.getElement().addEventListener('mouseleave', () => originMarker.togglePopup());
|
|
570
|
+
// Destination Marker (Delivery)
|
|
571
|
+
const elementForDestination = document.createElement('div');
|
|
572
|
+
elementForDestination.className = 'cursor-pointer active:scale-95 transition-transform duration-200 drop-shadow-lg';
|
|
573
|
+
const deliveryLabel = 'D';
|
|
574
|
+
elementForDestination.innerHTML = `
|
|
575
|
+
<svg width="30" height="38" viewBox="0 0 30 38" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
576
|
+
<path d="M15 0C6.71573 0 0 6.71573 0 15C0 26.25 15 38 15 38C15 38 30 26.25 30 15C30 6.71573 23.2843 0 15 0Z" fill="${routeDetails.linecolor}"/>
|
|
577
|
+
<circle cx="15" cy="15" r="9" fill="white"/>
|
|
578
|
+
<text x="15" y="19" text-anchor="middle" fill="black" style="font-family: Inter, sans-serif; font-size: 13px; font-weight: 800;">${deliveryLabel}</text>
|
|
579
|
+
</svg>
|
|
580
|
+
`;
|
|
581
|
+
const destinationMarker = new mapboxgl.Marker({ element: elementForDestination, anchor: 'bottom' })
|
|
582
|
+
.setPopup(popupForDestination)
|
|
583
|
+
.setLngLat(routeDetails.destination)
|
|
584
|
+
.addTo(this.map);
|
|
585
|
+
destinationMarker.getElement().addEventListener('mouseenter', () => destinationMarker.togglePopup());
|
|
586
|
+
destinationMarker.getElement().addEventListener('mouseleave', () => destinationMarker.togglePopup());
|
|
587
|
+
const id = `${routeDetails.routeType}-${routeDetails.index}`;
|
|
588
|
+
this.markerOriginList.set(id, originMarker);
|
|
589
|
+
this.markerDestinationList.set(id, destinationMarker);
|
|
590
|
+
// True 3D Elevated Arc Simulation Engine using Native SVG Overlays
|
|
591
|
+
try {
|
|
592
|
+
this.initSvgOverlay();
|
|
593
|
+
const pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
594
|
+
pathEl.setAttribute('fill', 'none');
|
|
595
|
+
pathEl.setAttribute('stroke-width', '3');
|
|
596
|
+
pathEl.style.cursor = 'pointer';
|
|
597
|
+
pathEl.style.pointerEvents = 'stroke'; // Allow interactivity!
|
|
598
|
+
const gradId = `arc-grad-${id}`;
|
|
599
|
+
const defs = this.svgOverlay.querySelector('defs');
|
|
600
|
+
let grad = defs.querySelector(`#${gradId}`);
|
|
601
|
+
if (!grad) {
|
|
602
|
+
grad = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
|
|
603
|
+
grad.setAttribute('id', gradId);
|
|
604
|
+
defs.appendChild(grad);
|
|
605
|
+
}
|
|
606
|
+
grad.innerHTML = `
|
|
607
|
+
<stop offset="0%" stop-color="${routeDetails.linecolor}" stop-opacity="1"/>
|
|
608
|
+
<stop offset="100%" stop-color="#ffffff" stop-opacity="0.8"/>
|
|
609
|
+
`;
|
|
610
|
+
pathEl.setAttribute('stroke', `url(#${gradId})`);
|
|
611
|
+
this.svgOverlay.appendChild(pathEl);
|
|
612
|
+
this.activeArcs[id] = {
|
|
613
|
+
origin: routeDetails.origin,
|
|
614
|
+
destination: routeDetails.destination,
|
|
615
|
+
color: routeDetails.linecolor,
|
|
616
|
+
pathEl
|
|
617
|
+
};
|
|
618
|
+
// Native tooltips hovering strictly matching V1 Deck.GL behaviors
|
|
619
|
+
pathEl.addEventListener('mouseenter', (e) => {
|
|
620
|
+
pathEl.setAttribute('stroke-width', '6');
|
|
621
|
+
// Find geo coordinate exactly under cursor natively
|
|
622
|
+
const rect = this.svgOverlay.getBoundingClientRect();
|
|
623
|
+
const lngLat = this.map.unproject([e.clientX - rect.left, e.clientY - rect.top]);
|
|
624
|
+
const payload = {
|
|
625
|
+
layer: { props: { data: { route: routeDetails.route, index: routeDetails.index, routeType: routeDetails.routeType } } },
|
|
626
|
+
coordinate: [lngLat.lng, lngLat.lat],
|
|
627
|
+
color: routeDetails.linecolor
|
|
628
|
+
};
|
|
629
|
+
this.showRoutePopup(payload, e, routeDetails.isViewRoute);
|
|
630
|
+
});
|
|
631
|
+
pathEl.addEventListener('mouseleave', () => {
|
|
632
|
+
pathEl.setAttribute('stroke-width', '3');
|
|
633
|
+
const payload = { color: null, layer: { props: { data: { index: routeDetails.index, routeType: routeDetails.routeType } } } };
|
|
634
|
+
this.showRoutePopup(payload, null, routeDetails.isViewRoute);
|
|
635
|
+
});
|
|
636
|
+
this.updateSvgPaths(); // Force plot
|
|
637
|
+
}
|
|
638
|
+
catch (e) {
|
|
639
|
+
console.warn("Native overarching arc generation skipped:", e);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
showRoutePopup(arcDetails, event, isViewRoute) {
|
|
643
|
+
const data = arcDetails.layer.props.data;
|
|
644
|
+
const layerId = isViewRoute
|
|
645
|
+
? `line${data.index}`
|
|
646
|
+
: `route-layer-${data.routeType || 'jobcode'}-${data.index}`;
|
|
647
|
+
if (this.popup) {
|
|
648
|
+
this.popup.remove();
|
|
649
|
+
if (this.map.getLayer(layerId)) {
|
|
650
|
+
this.map.setPaintProperty(layerId, 'line-width', 2);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (arcDetails.color && this.map.getLayer(layerId) && this.map.getLayoutProperty(layerId, 'visibility') !== 'none') {
|
|
654
|
+
this.map.setPaintProperty(layerId, 'line-width', 5);
|
|
655
|
+
// Removed line-opacity overwrite here because bezier lines inherit opacity and break if set raw on a gradient.
|
|
656
|
+
const datasetForPopup = {
|
|
657
|
+
coordinate: arcDetails.coordinate,
|
|
658
|
+
pickup: arcDetails.layer.props.data.route.pickup_location || '',
|
|
659
|
+
drop: arcDetails.layer.props.data.route.delivery_location || '',
|
|
660
|
+
jobCode: arcDetails.layer.props.data.route.project ? arcDetails.layer.props.data.route.order_number : '',
|
|
661
|
+
customer: arcDetails.layer.props.data.route.project ? arcDetails.layer.props.data.route.customer_name : '',
|
|
662
|
+
routeType: arcDetails.layer.props.data.route.project ? 'Project' : 'Route',
|
|
663
|
+
title: arcDetails.layer.props.data.route.project ? arcDetails.layer.props.data.route.project : arcDetails.layer.props.data.route.route_name || '',
|
|
664
|
+
material: arcDetails.layer.props.data.route.material || '',
|
|
665
|
+
type: arcDetails.layer.props.data.route.unit || '',
|
|
666
|
+
};
|
|
667
|
+
this.createPopup(datasetForPopup);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
createPopup(datasetForPopup) {
|
|
671
|
+
if (!this.map)
|
|
672
|
+
return;
|
|
673
|
+
this.popup = new mapboxgl.Popup({
|
|
674
|
+
closeButton: false,
|
|
675
|
+
closeOnClick: false,
|
|
676
|
+
closeOnMove: true,
|
|
677
|
+
anchor: 'bottom-left',
|
|
678
|
+
});
|
|
679
|
+
// Extract location short names
|
|
680
|
+
const pickupDisplay = datasetForPopup.pickup?.split('|')[1] || datasetForPopup.pickup || 'Unknown Pickup';
|
|
681
|
+
const dropDisplay = datasetForPopup.drop?.split('|')[1] || datasetForPopup.drop || 'Unknown Delivery';
|
|
682
|
+
this.popup
|
|
683
|
+
.setLngLat(datasetForPopup.coordinate)
|
|
684
|
+
.setHTML(`<div class="destination p-3 bg-white dark:bg-slate-800 rounded shadow-lg text-sm text-gray-800 dark:text-gray-200">
|
|
685
|
+
<div class="duration space-y-1 mb-2">
|
|
686
|
+
<p class="pickprt"><b class="text-gray-900 dark:text-white">Pickup Location:</b> ${pickupDisplay}</p>
|
|
687
|
+
<p class="dropprt"><b class="text-gray-900 dark:text-white">Drop Location:</b> ${dropDisplay}</p>
|
|
688
|
+
</div>
|
|
689
|
+
${datasetForPopup.jobCode ? `<span class="block"><b>Job Code:</b> ${datasetForPopup.jobCode}</span>` : ''}
|
|
690
|
+
${datasetForPopup.customer ? `<span class="block"><b>Customer:</b> ${datasetForPopup.customer}</span>` : ''}
|
|
691
|
+
<span class="block"><b>${datasetForPopup.routeType} Name:</b> ${datasetForPopup.title}</span>
|
|
692
|
+
${datasetForPopup.material ? `<span class="block"><b>Material:</b> ${datasetForPopup.material}</span>` : ''}
|
|
693
|
+
<span class="block"><b>Type:</b> ${datasetForPopup.type}</span>
|
|
694
|
+
</div>`)
|
|
695
|
+
.addTo(this.map);
|
|
696
|
+
}
|
|
697
|
+
// Draw Line
|
|
698
|
+
drawLine(cordinates, index, route, enablefitbound, routeType, isStyleRefresh) {
|
|
699
|
+
return new Promise((resolve) => {
|
|
700
|
+
if (!this.map || !this.isMapReady()) {
|
|
701
|
+
resolve();
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
// Calculate bounds for this specific route
|
|
705
|
+
const routeBounds = new mapboxgl.LngLatBounds();
|
|
706
|
+
if (cordinates && cordinates.length > 0) {
|
|
707
|
+
cordinates.forEach((coord) => routeBounds.extend(coord));
|
|
708
|
+
}
|
|
709
|
+
const registryId = `${routeType}-${index}`;
|
|
710
|
+
// Register the route with its coordinates and pre-calculated bounds
|
|
711
|
+
this.activeRoutesRegistry.set(registryId, {
|
|
712
|
+
cordinates,
|
|
713
|
+
route,
|
|
714
|
+
routeType,
|
|
715
|
+
bounds: routeBounds,
|
|
716
|
+
index
|
|
717
|
+
});
|
|
718
|
+
let origin = cordinates[0];
|
|
719
|
+
let destination = cordinates[cordinates.length - 1];
|
|
720
|
+
if (origin[0] && origin[1] && destination && destination[0] && destination[1]) {
|
|
721
|
+
// Execute plotting logic IMMEDIATELY to trigger the map's render cycle
|
|
722
|
+
const linecolor = this.provideLineColor(route['unit'], routeType);
|
|
668
723
|
if (enablefitbound) {
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
right: this.padding.right,
|
|
676
|
-
};
|
|
677
|
-
this.map.fitBounds([origin, destination], { padding, pitch: 65 }, { fitboundCompleteJob: true });
|
|
724
|
+
const padTop = Math.max(0, (this.padding?.top || 0) + this.customTopForCustomer + 50);
|
|
725
|
+
const padBot = Math.max(0, (this.padding?.bottom || 0) + (this.windowActualHeightWidth.availHeight - (window.innerHeight - 65)) + 50);
|
|
726
|
+
const padLeft = Math.max(0, (this.padding?.left || 0) + 350);
|
|
727
|
+
const padRight = Math.max(0, (this.padding?.right || 0) + 50);
|
|
728
|
+
const customPadding = { top: padTop, bottom: padBot, left: padLeft, right: padRight };
|
|
729
|
+
this.map.fitBounds([origin, destination], { padding: customPadding, pitch: 65 }, { fitboundCompleteJob: true });
|
|
678
730
|
}
|
|
679
|
-
|
|
680
|
-
|
|
731
|
+
const sourceId = `route-source-${routeType}-${index}`;
|
|
732
|
+
const layerId = `route-layer-${routeType}-${index}`;
|
|
733
|
+
if (this.map.getSource(sourceId)) {
|
|
734
|
+
this.removeRouteAndMarker(index, routeType).then(() => { });
|
|
681
735
|
}
|
|
682
|
-
this.map.addSource(
|
|
736
|
+
this.map.addSource(sourceId, {
|
|
683
737
|
type: 'geojson',
|
|
684
738
|
data: {
|
|
685
739
|
type: 'Feature',
|
|
@@ -688,51 +742,54 @@ class CoolmapService {
|
|
|
688
742
|
},
|
|
689
743
|
});
|
|
690
744
|
this.map.addLayer({
|
|
691
|
-
id:
|
|
745
|
+
id: layerId,
|
|
692
746
|
type: 'line',
|
|
693
|
-
source:
|
|
747
|
+
source: sourceId,
|
|
694
748
|
paint: { 'line-color': linecolor, 'line-width': 2 },
|
|
695
749
|
layout: { 'line-cap': 'round', 'line-join': 'round' },
|
|
696
750
|
});
|
|
697
|
-
|
|
698
|
-
origin,
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
};
|
|
704
|
-
this.createMarker(dataSetForMap);
|
|
705
|
-
this.map.on('mouseenter', `route-for-job-code${index}`, (e) => {
|
|
706
|
-
if (this.popup) {
|
|
751
|
+
if (!isStyleRefresh) {
|
|
752
|
+
const dataSetForMap = { origin, destination, index, linecolor, route, routeType };
|
|
753
|
+
this.createMarker(dataSetForMap);
|
|
754
|
+
}
|
|
755
|
+
this.map.on('mouseenter', layerId, (e) => {
|
|
756
|
+
if (this.popup)
|
|
707
757
|
this.popup.remove();
|
|
708
|
-
|
|
709
|
-
this.map.setPaintProperty(
|
|
710
|
-
this.map.setPaintProperty(`route-for-job-code${index}`, 'line-opacity', 1);
|
|
758
|
+
this.map.setPaintProperty(layerId, 'line-width', 5);
|
|
759
|
+
this.map.setPaintProperty(layerId, 'line-opacity', 1);
|
|
711
760
|
const datasetForPopup = {
|
|
712
761
|
coordinate: [e.lngLat.lng, e.lngLat.lat],
|
|
713
|
-
pickup: route.pickup_location
|
|
714
|
-
drop: route.delivery_location
|
|
762
|
+
pickup: route.pickup_location || '',
|
|
763
|
+
drop: route.delivery_location || '',
|
|
715
764
|
jobCode: route.project ? route.order_number : null,
|
|
716
765
|
customer: route.project ? route.customer_name : null,
|
|
717
766
|
routeType: route.project ? 'Project' : 'Route',
|
|
718
|
-
title: route.project
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
? route.route_name
|
|
722
|
-
: '',
|
|
723
|
-
material: route.material ? route.material : '',
|
|
724
|
-
type: route.unit ? route.unit : '',
|
|
767
|
+
title: route.project ? route.project : route.route_name || '',
|
|
768
|
+
material: route.material || '',
|
|
769
|
+
type: route.unit || '',
|
|
725
770
|
};
|
|
726
771
|
this.createPopup(datasetForPopup);
|
|
727
772
|
});
|
|
728
|
-
this.map.on('mouseleave',
|
|
729
|
-
this.map.setPaintProperty(
|
|
730
|
-
if (this.popup)
|
|
773
|
+
this.map.on('mouseleave', layerId, () => {
|
|
774
|
+
this.map.setPaintProperty(layerId, 'line-width', 2);
|
|
775
|
+
if (this.popup)
|
|
731
776
|
this.popup.remove();
|
|
732
|
-
}
|
|
733
777
|
});
|
|
734
|
-
|
|
735
|
-
|
|
778
|
+
// SAFETY: Use a timeout to ensure resolve() is always called even if 'idle' event skips
|
|
779
|
+
let resolved = false;
|
|
780
|
+
const complete = () => {
|
|
781
|
+
if (!resolved) {
|
|
782
|
+
resolved = true;
|
|
783
|
+
resolve();
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
this.map.once('idle', complete);
|
|
787
|
+
setTimeout(complete, 500); // 500ms safety timeout
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
resolve();
|
|
791
|
+
}
|
|
792
|
+
});
|
|
736
793
|
}
|
|
737
794
|
provideLineColor(unitType, type) {
|
|
738
795
|
let checkType = type && !['jobrouteList', 'addroute'].includes(type) ? true : false;
|
|
@@ -747,83 +804,12 @@ class CoolmapService {
|
|
|
747
804
|
case 'Hourly':
|
|
748
805
|
color = checkType ? '#ffad56' : '#ae23d1';
|
|
749
806
|
break;
|
|
807
|
+
default:
|
|
808
|
+
color = '#3b82f6';
|
|
809
|
+
break;
|
|
750
810
|
}
|
|
751
811
|
return color;
|
|
752
812
|
}
|
|
753
|
-
showRoutePopup(arcDetails, event, isViewRoute) {
|
|
754
|
-
if (this.popup) {
|
|
755
|
-
this.popup.remove();
|
|
756
|
-
this.map.setPaintProperty(`${isViewRoute ? 'line' : 'route-for-job-code'}${arcDetails.layer.props.data.index}`, 'line-width', 2);
|
|
757
|
-
}
|
|
758
|
-
if (arcDetails.color &&
|
|
759
|
-
this.map.getLayoutProperty(arcDetails.layer.id, 'visibility') !== 'none') {
|
|
760
|
-
this.map.setPaintProperty(`${isViewRoute ? 'line' : 'route-for-job-code'}${arcDetails.layer.props.data.index}`, 'line-width', 5);
|
|
761
|
-
this.map.setPaintProperty(`${isViewRoute ? 'line' : 'route-for-job-code'}${arcDetails.layer.props.data.index}`, 'line-opacity', 1);
|
|
762
|
-
const datasetForPopup = {
|
|
763
|
-
coordinate: arcDetails.coordinate,
|
|
764
|
-
pickup: arcDetails.layer.props.data.route.pickup_location
|
|
765
|
-
? arcDetails.layer.props.data.route.pickup_location
|
|
766
|
-
: '',
|
|
767
|
-
drop: arcDetails.layer.props.data.route.delivery_location
|
|
768
|
-
? arcDetails.layer.props.data.route.delivery_location
|
|
769
|
-
: '',
|
|
770
|
-
jobCode: arcDetails.layer.props.data.route.project
|
|
771
|
-
? arcDetails.layer.props.data.route.order_number
|
|
772
|
-
: '',
|
|
773
|
-
customer: arcDetails.layer.props.data.route.project
|
|
774
|
-
? arcDetails.layer.props.data.route.customer_name
|
|
775
|
-
: '',
|
|
776
|
-
routeType: arcDetails.layer.props.data.route.project
|
|
777
|
-
? 'Project'
|
|
778
|
-
: 'Route',
|
|
779
|
-
title: arcDetails.layer.props.data.route.project
|
|
780
|
-
? arcDetails.layer.props.data.route.project
|
|
781
|
-
: arcDetails.layer.props.data.route.route_name
|
|
782
|
-
? arcDetails.layer.props.data.route.route_name
|
|
783
|
-
: '',
|
|
784
|
-
material: arcDetails.layer.props.data.route.material
|
|
785
|
-
? arcDetails.layer.props.data.route.material
|
|
786
|
-
: '',
|
|
787
|
-
type: arcDetails.layer.props.data.route.unit
|
|
788
|
-
? arcDetails.layer.props.data.route.unit
|
|
789
|
-
: '',
|
|
790
|
-
};
|
|
791
|
-
this.createPopup(datasetForPopup);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
createPopup(datasetForPopup) {
|
|
795
|
-
this.popup = new mapboxgl.Popup({
|
|
796
|
-
closeButton: false,
|
|
797
|
-
closeOnClick: false,
|
|
798
|
-
closeOnMove: true,
|
|
799
|
-
anchor: 'bottom-left',
|
|
800
|
-
});
|
|
801
|
-
this.popup
|
|
802
|
-
.setLngLat(datasetForPopup.coordinate)
|
|
803
|
-
.setHTML(`<div class="destination">
|
|
804
|
-
<div class="duration">
|
|
805
|
-
<p class="pickprt"><b>Pickup Location:</b> ${datasetForPopup.pickup?.split('|')[1] ? datasetForPopup.pickup.split('|')[1] : datasetForPopup.pickup}</p>
|
|
806
|
-
<p class="dropprt"><b>Drop Location:</b> ${datasetForPopup.drop?.split('|')[1] ?
|
|
807
|
-
datasetForPopup.drop.split('|')[1] :
|
|
808
|
-
datasetForPopup.drop}</p>
|
|
809
|
-
</div>
|
|
810
|
-
${datasetForPopup.jobCode
|
|
811
|
-
? '<span><b>Job Code:</b> ' + datasetForPopup.jobCode + '</span>'
|
|
812
|
-
: ''}
|
|
813
|
-
${datasetForPopup.customer
|
|
814
|
-
? '<span><b>Customer:</b> ' + datasetForPopup.customer + '</span>'
|
|
815
|
-
: ''}
|
|
816
|
-
<span>
|
|
817
|
-
<b>${datasetForPopup.routeType} Name:</b>
|
|
818
|
-
${datasetForPopup.title}
|
|
819
|
-
</span>
|
|
820
|
-
${datasetForPopup.material
|
|
821
|
-
? '<span><b>Material:</b> ' + datasetForPopup.material + '</span>'
|
|
822
|
-
: ''}
|
|
823
|
-
<span><b>Type:</b> ${datasetForPopup.type}</span>
|
|
824
|
-
</div>`)
|
|
825
|
-
.addTo(this.map);
|
|
826
|
-
}
|
|
827
813
|
hexToRGB(hex) {
|
|
828
814
|
return hex
|
|
829
815
|
.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, (m, r, g, b) => '#' + r + r + g + g + b + b)
|
|
@@ -831,105 +817,143 @@ class CoolmapService {
|
|
|
831
817
|
.match(/.{2}/g)
|
|
832
818
|
.map((x) => parseInt(x, 16));
|
|
833
819
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
820
|
+
// --- SVG 3D Engine Methods ---
|
|
821
|
+
initSvgOverlay() {
|
|
822
|
+
if (this.svgOverlay || !this.mapContainer)
|
|
823
|
+
return;
|
|
824
|
+
this.svgOverlay = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
825
|
+
this.svgOverlay.style.position = 'absolute';
|
|
826
|
+
this.svgOverlay.style.top = '0';
|
|
827
|
+
this.svgOverlay.style.left = '0';
|
|
828
|
+
this.svgOverlay.style.width = '100%';
|
|
829
|
+
this.svgOverlay.style.height = '100%';
|
|
830
|
+
this.svgOverlay.style.pointerEvents = 'none';
|
|
831
|
+
this.svgOverlay.style.zIndex = '10';
|
|
832
|
+
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
|
833
|
+
this.svgOverlay.appendChild(defs);
|
|
834
|
+
this.mapContainer.appendChild(this.svgOverlay);
|
|
835
|
+
this.map.on('render', () => this.updateSvgPaths());
|
|
836
|
+
}
|
|
837
|
+
updateSvgPaths() {
|
|
838
|
+
if (!this.svgOverlay || !this.map)
|
|
839
|
+
return;
|
|
840
|
+
for (const key in this.activeArcs) {
|
|
841
|
+
const arc = this.activeArcs[key];
|
|
842
|
+
const p1 = this.map.project(arc.origin);
|
|
843
|
+
const p2 = this.map.project(arc.destination);
|
|
844
|
+
// Safety Guard: Check for Infinity and extreme numbers (Number.MAX_VALUE)
|
|
845
|
+
// which Mapbox can return during transitions.
|
|
846
|
+
// 1e15 is a safe threshold for JS math and SVG rendering engines.
|
|
847
|
+
const isUsable = (p) => Number.isFinite(p.x) && Math.abs(p.x) < 1e15 &&
|
|
848
|
+
Number.isFinite(p.y) && Math.abs(p.y) < 1e15;
|
|
849
|
+
if (!isUsable(p1) || !isUsable(p2))
|
|
850
|
+
continue;
|
|
851
|
+
const dx = p2.x - p1.x;
|
|
852
|
+
const dy = p2.y - p1.y;
|
|
853
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
854
|
+
// Secondary check for distance finiteness
|
|
855
|
+
if (!Number.isFinite(dist) || dist > 1e15)
|
|
856
|
+
continue;
|
|
857
|
+
const mx = (p1.x + p2.x) / 2;
|
|
858
|
+
let controlY = ((p1.y + p2.y) / 2) - (dist * 1.05);
|
|
859
|
+
// Final sanity check for calculated curve peaks
|
|
860
|
+
controlY = Math.max(100, controlY);
|
|
861
|
+
if (!Number.isFinite(controlY) || !Number.isFinite(mx))
|
|
862
|
+
continue;
|
|
863
|
+
// Update with rounded values to ensure clean and valid attribute data
|
|
864
|
+
arc.pathEl.setAttribute('d', `M ${p1.x.toFixed(2)} ${p1.y.toFixed(2)} Q ${mx.toFixed(2)} ${controlY.toFixed(2)} ${p2.x.toFixed(2)} ${p2.y.toFixed(2)}`);
|
|
865
|
+
// Sync the gradient positioning physically mapped to coordinate space
|
|
866
|
+
const grad = this.svgOverlay.querySelector(`#arc-grad-${key}`);
|
|
867
|
+
if (grad) {
|
|
868
|
+
const minX = Math.min(p1.x, p2.x);
|
|
869
|
+
const maxX = Math.max(p1.x, p2.x);
|
|
870
|
+
const minY = Math.min(p1.y, p2.y, controlY);
|
|
871
|
+
const maxY = Math.max(p1.y, p2.y, controlY);
|
|
872
|
+
const w = Math.max(1, maxX - minX);
|
|
873
|
+
const h = Math.max(1, maxY - minY);
|
|
874
|
+
grad.setAttribute('x1', `${((p1.x - minX) / w) * 100}%`);
|
|
875
|
+
grad.setAttribute('y1', `${((p1.y - minY) / h) * 100}%`);
|
|
876
|
+
grad.setAttribute('x2', `${((p2.x - minX) / w) * 100}%`);
|
|
877
|
+
grad.setAttribute('y2', `${((p2.y - minY) / h) * 100}%`);
|
|
878
|
+
}
|
|
885
879
|
}
|
|
886
880
|
}
|
|
887
|
-
async removeRouteAndMarker(index) {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
this.map.getLayer(`line${index}`)
|
|
893
|
-
? this.map.removeLayer(`line${index}`)
|
|
894
|
-
: '';
|
|
895
|
-
this.map.getLayer(`custom_layer${index}`)
|
|
896
|
-
? this.map.removeLayer(`custom_layer${index}`)
|
|
897
|
-
: '';
|
|
898
|
-
this.map.getSource(`line${index}`)
|
|
899
|
-
? this.map.removeSource(`line${index}`)
|
|
900
|
-
: '';
|
|
901
|
-
this.map.getLayer(`route-for-job-code${index}`)
|
|
902
|
-
? this.map.removeLayer(`route-for-job-code${index}`)
|
|
903
|
-
: '';
|
|
904
|
-
this.map.getSource(`route-source-for-job-code${index}`)
|
|
905
|
-
? this.map.removeSource(`route-source-for-job-code${index}`)
|
|
906
|
-
: '';
|
|
907
|
-
this.findMarkerBound(index);
|
|
908
|
-
this.markerOriginList[index] ? this.markerOriginList[index].remove() : '';
|
|
909
|
-
this.markerDestinationList[index]
|
|
910
|
-
? this.markerDestinationList[index].remove()
|
|
911
|
-
: '';
|
|
912
|
-
await true;
|
|
881
|
+
async removeRouteAndMarker(index, routeType = 'jobcode') {
|
|
882
|
+
const registryId = `${routeType}-${index}`;
|
|
883
|
+
// Clean up registry
|
|
884
|
+
if (this.activeRoutesRegistry.has(registryId)) {
|
|
885
|
+
this.activeRoutesRegistry.delete(registryId);
|
|
913
886
|
}
|
|
887
|
+
if (!this.map)
|
|
888
|
+
return true;
|
|
889
|
+
try {
|
|
890
|
+
if (this.activeArcs[registryId]) {
|
|
891
|
+
const arc = this.activeArcs[registryId];
|
|
892
|
+
if (arc.pathEl.parentNode)
|
|
893
|
+
arc.pathEl.parentNode.removeChild(arc.pathEl);
|
|
894
|
+
delete this.activeArcs[registryId];
|
|
895
|
+
}
|
|
896
|
+
if (this.svgOverlay) {
|
|
897
|
+
const grad = this.svgOverlay.querySelector(`defs #arc-grad-${registryId}`);
|
|
898
|
+
if (grad && grad.parentNode)
|
|
899
|
+
grad.parentNode.removeChild(grad);
|
|
900
|
+
}
|
|
901
|
+
const layerId = `route-layer-${routeType}-${index}`;
|
|
902
|
+
const sourceId = `route-source-${routeType}-${index}`;
|
|
903
|
+
this.map.getLayer(layerId) ? this.map.removeLayer(layerId) : null;
|
|
904
|
+
this.map.getLayer(`line${index}`) ? this.map.removeLayer(`line${index}`) : null;
|
|
905
|
+
this.map.getSource(sourceId) ? this.map.removeSource(sourceId) : null;
|
|
906
|
+
this.map.getSource(`line${index}`) ? this.map.removeSource(`line${index}`) : null;
|
|
907
|
+
this.markerOriginList.get(registryId)?.remove();
|
|
908
|
+
this.markerOriginList.delete(registryId);
|
|
909
|
+
this.markerDestinationList.get(registryId)?.remove();
|
|
910
|
+
this.markerDestinationList.delete(registryId);
|
|
911
|
+
this.markerOriginList.get(String(index))?.remove();
|
|
912
|
+
this.markerDestinationList.get(String(index))?.remove();
|
|
913
|
+
if (this.popup)
|
|
914
|
+
this.popup.remove();
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
catch (e) {
|
|
918
|
+
console.warn('Error removing route/marker:', e);
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
reAddLayers() {
|
|
923
|
+
this.activeRoutesRegistry.forEach((data, regId) => {
|
|
924
|
+
// Use the stored raw index instead of the composite registry key
|
|
925
|
+
this.drawLine(data.cordinates, data.index, data.route, false, data.routeType, true);
|
|
926
|
+
});
|
|
914
927
|
}
|
|
915
928
|
findMarkerBound(index) {
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
if (
|
|
921
|
-
this.originDestinationCordinates.
|
|
929
|
+
const id = String(index);
|
|
930
|
+
const originMarker = this.markerOriginList.get(id);
|
|
931
|
+
const originLng = originMarker?.getLngLat()?.lng;
|
|
932
|
+
const originLat = originMarker?.getLngLat()?.lat;
|
|
933
|
+
if (originLng !== undefined && originLat !== undefined) {
|
|
934
|
+
const indexOfCordinates = this.originDestinationCordinates.findIndex((x) => x[0][0].toFixed(6) === originLng.toFixed(6) &&
|
|
935
|
+
x[0][1].toFixed(6) === originLat.toFixed(6));
|
|
936
|
+
if (indexOfCordinates >= 0) {
|
|
937
|
+
this.originDestinationCordinates.splice(indexOfCordinates, 1);
|
|
938
|
+
}
|
|
922
939
|
}
|
|
923
940
|
}
|
|
924
941
|
async filterRoute(ID, visibility, showAllFitbound) {
|
|
925
|
-
if (ID) {
|
|
942
|
+
if (ID && this.map) {
|
|
926
943
|
if (this.map.getLayer(`route-for-job-code${ID}`)) {
|
|
927
944
|
this.map.setLayoutProperty(`route-for-job-code${ID}`, 'visibility', visibility);
|
|
928
|
-
const
|
|
929
|
-
originM
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
945
|
+
const id = String(ID);
|
|
946
|
+
const originM = this.markerOriginList.get(id);
|
|
947
|
+
if (originM) {
|
|
948
|
+
originM.getElement().style.display = visibility === 'visible' ? 'block' : 'none';
|
|
949
|
+
}
|
|
950
|
+
const destinationM = this.markerDestinationList.get(id);
|
|
951
|
+
if (destinationM) {
|
|
952
|
+
destinationM.getElement().style.display = visibility === 'visible' ? 'block' : 'none';
|
|
953
|
+
}
|
|
954
|
+
if (this.activeArcs[ID]) {
|
|
955
|
+
this.activeArcs[ID].pathEl.style.display = visibility === 'visible' ? 'block' : 'none';
|
|
956
|
+
}
|
|
933
957
|
if (visibility === 'none' && showAllFitbound) {
|
|
934
958
|
this.findMarkerBound(ID);
|
|
935
959
|
this.extendReBound();
|
|
@@ -939,36 +963,32 @@ class CoolmapService {
|
|
|
939
963
|
this.map.setLayoutProperty(`arc-layer${ID}`, 'visibility', visibility);
|
|
940
964
|
}
|
|
941
965
|
}
|
|
942
|
-
|
|
966
|
+
return true;
|
|
943
967
|
}
|
|
944
968
|
extendBound(route, showAllFitbound) {
|
|
945
|
-
return new Promise((resolve
|
|
946
|
-
if (route) {
|
|
969
|
+
return new Promise((resolve) => {
|
|
970
|
+
if (route && this.map) {
|
|
947
971
|
if (typeof route === 'string') {
|
|
948
972
|
let path = route.split(';');
|
|
949
|
-
path = path.map((ele) =>
|
|
950
|
-
|
|
951
|
-
});
|
|
952
|
-
path.forEach((ele, index) => {
|
|
953
|
-
if (ele.length === 1)
|
|
954
|
-
path.splice(index, 1);
|
|
955
|
-
});
|
|
973
|
+
path = path.map((ele) => this.formateLatLong(ele));
|
|
974
|
+
path = path.filter((ele) => ele && ele.length > 1);
|
|
956
975
|
route = path;
|
|
957
976
|
}
|
|
958
|
-
if (route[0][0] &&
|
|
959
|
-
route[0][1] &&
|
|
960
|
-
route[route.length - 1][0] &&
|
|
961
|
-
route[route.length - 1][1]) {
|
|
977
|
+
if (route[0] && route[0][0] && route[0][1] && route[route.length - 1] && route[route.length - 1][0] && route[route.length - 1][1]) {
|
|
962
978
|
this.originDestinationCordinates.push(route);
|
|
963
|
-
|
|
964
|
-
|
|
979
|
+
this.bounds = new mapboxgl.LngLatBounds();
|
|
980
|
+
this.originDestinationCordinates.forEach((routeItem) => {
|
|
981
|
+
routeItem.forEach((coord) => {
|
|
982
|
+
this.bounds.extend(coord);
|
|
983
|
+
});
|
|
965
984
|
});
|
|
966
985
|
}
|
|
967
986
|
}
|
|
968
|
-
if (showAllFitbound) {
|
|
987
|
+
if (showAllFitbound && this.map) {
|
|
969
988
|
setTimeout(() => {
|
|
970
|
-
if (showAllFitbound &&
|
|
971
|
-
this.map.fitBounds(this.bounds, { pitch: 65 }, { fitboundComplete: true });
|
|
989
|
+
if (showAllFitbound && !this.bounds.isEmpty()) {
|
|
990
|
+
this.map.fitBounds(this.bounds, { pitch: 65, maxZoom: 14, padding: 90 }, { fitboundComplete: true });
|
|
991
|
+
}
|
|
972
992
|
}, 100);
|
|
973
993
|
this.map.once('moveend', (event) => {
|
|
974
994
|
if (event.fitboundComplete) {
|
|
@@ -976,28 +996,32 @@ class CoolmapService {
|
|
|
976
996
|
}
|
|
977
997
|
});
|
|
978
998
|
}
|
|
999
|
+
else {
|
|
1000
|
+
resolve(true);
|
|
1001
|
+
}
|
|
979
1002
|
});
|
|
980
1003
|
}
|
|
981
1004
|
extendReBound(bottom) {
|
|
982
|
-
return new Promise((resolve
|
|
1005
|
+
return new Promise((resolve) => {
|
|
983
1006
|
this.bounds = new mapboxgl.LngLatBounds();
|
|
984
|
-
if (this.originDestinationCordinates.length
|
|
985
|
-
this.originDestinationCordinates.
|
|
986
|
-
item.
|
|
1007
|
+
if (this.originDestinationCordinates.length > 0) {
|
|
1008
|
+
this.originDestinationCordinates.forEach((item, index) => {
|
|
1009
|
+
item.forEach((route) => {
|
|
987
1010
|
this.bounds.extend(route);
|
|
988
1011
|
});
|
|
989
1012
|
if (index === this.originDestinationCordinates.length - 1) {
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
right:
|
|
1013
|
+
const padTop = Math.max(0, (this.padding?.top || 0) + this.customTopForCustomer + 80);
|
|
1014
|
+
const padBot = Math.max(0, (this.padding?.bottom || 0) + (this.windowActualHeightWidth.availHeight - (window.innerHeight - 65)) + 80);
|
|
1015
|
+
const padLeft = Math.max(0, (this.padding?.left || 0) + 350);
|
|
1016
|
+
const padRight = Math.max(0, (this.padding?.right || 0) + 80);
|
|
1017
|
+
const customPadding = {
|
|
1018
|
+
top: padTop, bottom: padBot,
|
|
1019
|
+
left: padLeft, right: padRight,
|
|
997
1020
|
};
|
|
998
1021
|
setTimeout(() => {
|
|
999
|
-
if (this.originDestinationCordinates.length > 0)
|
|
1000
|
-
this.map.fitBounds(this.bounds, { padding, pitch: 65 });
|
|
1022
|
+
if (this.originDestinationCordinates.length > 0 && !this.bounds.isEmpty() && this.map) {
|
|
1023
|
+
this.map.fitBounds(this.bounds, { padding: customPadding, pitch: 65, maxZoom: 14 });
|
|
1024
|
+
}
|
|
1001
1025
|
}, 500);
|
|
1002
1026
|
resolve(true);
|
|
1003
1027
|
}
|
|
@@ -1008,52 +1032,209 @@ class CoolmapService {
|
|
|
1008
1032
|
}
|
|
1009
1033
|
});
|
|
1010
1034
|
}
|
|
1011
|
-
plotRoute(route, i, type, enablefitbound, showAllFitbound) {
|
|
1035
|
+
async plotRoute(route, i, type, enablefitbound, showAllFitbound) {
|
|
1036
|
+
const cacheKey = route['job_id'] || route['route_id'];
|
|
1037
|
+
// 1. Check cache FIRST
|
|
1038
|
+
if (this.pathCache.has(cacheKey)) {
|
|
1039
|
+
const path = this.pathCache.get(cacheKey);
|
|
1040
|
+
route['path'] = path;
|
|
1041
|
+
this.extendBound(path, showAllFitbound);
|
|
1042
|
+
await this.drawLine(path, i, route, enablefitbound, type);
|
|
1043
|
+
route['index'] = i;
|
|
1044
|
+
return true;
|
|
1045
|
+
}
|
|
1046
|
+
// 2. Check for inline path (Avoid API if already available)
|
|
1047
|
+
if (route['path'] && (Array.isArray(route['path']) || typeof route['path'] === 'string')) {
|
|
1048
|
+
let path = typeof route['path'] === 'string' ? route['path'].split(';') : route['path'];
|
|
1049
|
+
if (Array.isArray(path) && path.length > 0) {
|
|
1050
|
+
// Format if they are still strings
|
|
1051
|
+
if (typeof path[0] === 'string') {
|
|
1052
|
+
path = path.map((ele) => this.formateLatLong(ele));
|
|
1053
|
+
path = path.filter((ele) => ele && ele.length > 1);
|
|
1054
|
+
}
|
|
1055
|
+
if (path.length > 0) {
|
|
1056
|
+
this.pathCache.set(cacheKey, path);
|
|
1057
|
+
route['path'] = path;
|
|
1058
|
+
this.extendBound(path, showAllFitbound);
|
|
1059
|
+
await this.drawLine(path, i, route, enablefitbound, type);
|
|
1060
|
+
route['index'] = i;
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
// 3. Fallback to API call ONLY for jobcode (if path was missing)
|
|
1012
1066
|
return new Promise((resolve, reject) => {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
if (err) {
|
|
1067
|
+
if (['jobcode'].includes(type) || route['job_id']) {
|
|
1068
|
+
let param = { job: route['job_id'] };
|
|
1069
|
+
this.utils.postDataWithRestUrl('schedule/job/path', param).subscribe({
|
|
1070
|
+
next: async (res) => {
|
|
1071
|
+
let path = [];
|
|
1072
|
+
if (res['data'] && res['data']['route']) {
|
|
1073
|
+
path = res['data']['route'].split(';');
|
|
1074
|
+
path = path.map((ele) => this.formateLatLong(ele));
|
|
1075
|
+
path = path.filter((ele) => ele && ele.length > 1);
|
|
1076
|
+
this.pathCache.set(cacheKey, path);
|
|
1077
|
+
}
|
|
1078
|
+
if (path && path.length > 0) {
|
|
1079
|
+
route['path'] = path;
|
|
1080
|
+
this.extendBound(route['path'], showAllFitbound);
|
|
1081
|
+
await this.drawLine(route['path'], i, route, enablefitbound, type);
|
|
1082
|
+
route['index'] = i;
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
this.extendBound(null, showAllFitbound);
|
|
1086
|
+
}
|
|
1087
|
+
resolve(true);
|
|
1088
|
+
},
|
|
1089
|
+
error: (err) => {
|
|
1090
|
+
console.warn('Failed path retrieval', err);
|
|
1038
1091
|
reject(false);
|
|
1039
1092
|
}
|
|
1040
1093
|
});
|
|
1041
1094
|
}
|
|
1042
|
-
else
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1095
|
+
else {
|
|
1096
|
+
this.extendBound(null, showAllFitbound);
|
|
1097
|
+
resolve(true);
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Batch toggle visibility for routes on the map.
|
|
1103
|
+
* If visibleIds is empty, shows everything in the registry.
|
|
1104
|
+
* Otherwise, shows only those in visibleIds and hides the rest.
|
|
1105
|
+
*/
|
|
1106
|
+
setRoutesVisibility(visibleIds, showAllOverride, prefix) {
|
|
1107
|
+
const showAll = showAllOverride !== undefined ? showAllOverride : (visibleIds.length === 0);
|
|
1108
|
+
this.activeRoutesRegistry.forEach((data, id) => {
|
|
1109
|
+
const registryId = String(id).trim();
|
|
1110
|
+
// If a prefix is provided, only operate on routes matching that prefix.
|
|
1111
|
+
if (prefix && !registryId.startsWith(`${prefix}-`)) {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const isVisible = showAll || visibleIds.includes(registryId);
|
|
1115
|
+
const visibility = isVisible ? 'visible' : 'none';
|
|
1116
|
+
const display = isVisible ? 'block' : 'none';
|
|
1117
|
+
// Toggle New Layer Format
|
|
1118
|
+
const newLayerId = `route-layer-${data.routeType}-${data.index || id}`;
|
|
1119
|
+
if (this.map.getLayer(newLayerId)) {
|
|
1120
|
+
this.map.setLayoutProperty(newLayerId, 'visibility', visibility);
|
|
1121
|
+
}
|
|
1122
|
+
// Legacy/Alternate Layer Formats
|
|
1123
|
+
const legacyId = `route-for-job-code${id}`;
|
|
1124
|
+
if (this.map.getLayer(legacyId)) {
|
|
1125
|
+
this.map.setLayoutProperty(legacyId, 'visibility', visibility);
|
|
1126
|
+
}
|
|
1127
|
+
if (this.map.getLayer(`line${id}`)) {
|
|
1128
|
+
this.map.setLayoutProperty(`line${id}`, 'visibility', visibility);
|
|
1129
|
+
}
|
|
1130
|
+
// Toggle Markers
|
|
1131
|
+
const originM = this.markerOriginList.get(registryId);
|
|
1132
|
+
if (originM)
|
|
1133
|
+
originM.getElement().style.display = display;
|
|
1134
|
+
const destM = this.markerDestinationList.get(registryId);
|
|
1135
|
+
if (destM)
|
|
1136
|
+
destM.getElement().style.display = display;
|
|
1137
|
+
// Toggle Arcs
|
|
1138
|
+
if (this.activeArcs[registryId]) {
|
|
1139
|
+
this.activeArcs[registryId].pathEl.style.display = display;
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
// Recalculate bounds based on visible routes
|
|
1143
|
+
this.recalculateVisibleBounds(visibleIds);
|
|
1144
|
+
}
|
|
1145
|
+
recalculateVisibleBounds(visibleIds) {
|
|
1146
|
+
const showAll = visibleIds.length === 0;
|
|
1147
|
+
this.bounds = new mapboxgl.LngLatBounds();
|
|
1148
|
+
this.originDestinationCordinates = [];
|
|
1149
|
+
const normalizedVisibleIds = visibleIds.map(vid => String(vid).trim());
|
|
1150
|
+
this.activeRoutesRegistry.forEach((data, id) => {
|
|
1151
|
+
const registryId = String(id).trim();
|
|
1152
|
+
if (showAll || normalizedVisibleIds.includes(registryId)) {
|
|
1153
|
+
if (data.bounds && !data.bounds.isEmpty()) {
|
|
1154
|
+
this.bounds.extend(data.bounds);
|
|
1155
|
+
this.originDestinationCordinates.push(data.cordinates);
|
|
1156
|
+
}
|
|
1157
|
+
else if (data.cordinates && data.cordinates.length > 0) {
|
|
1158
|
+
// Fallback if bounds weren't pre-calculated
|
|
1159
|
+
data.cordinates.forEach((coord) => this.bounds.extend(coord));
|
|
1160
|
+
this.originDestinationCordinates.push(data.cordinates);
|
|
1054
1161
|
}
|
|
1055
1162
|
}
|
|
1056
1163
|
});
|
|
1164
|
+
if (!this.bounds.isEmpty() && this.map) {
|
|
1165
|
+
const canvas = this.map.getCanvas();
|
|
1166
|
+
const mapW = canvas.clientWidth;
|
|
1167
|
+
const mapH = canvas.clientHeight;
|
|
1168
|
+
let padTop = Math.max(0, (Number(this.padding?.top) || 0) + (Number(this.customTopForCustomer) || 0) + 80);
|
|
1169
|
+
let padBot = Math.max(0, (Number(this.padding?.bottom) || 0) + (Math.max(0, Number(this.windowActualHeightWidth.availHeight) - (Number(window.innerHeight) - 65))) + 80);
|
|
1170
|
+
let padLeft = Math.max(0, (Number(this.padding?.left) || 0) + (window.innerWidth > 1000 ? 350 : 50));
|
|
1171
|
+
let padRight = Math.max(0, (Number(this.padding?.right) || 0) + 80);
|
|
1172
|
+
// Safety Clamps: Ensure padding doesn't exceed canvas size
|
|
1173
|
+
const maxHorizPad = mapW * 0.8;
|
|
1174
|
+
const maxVertPad = mapH * 0.8;
|
|
1175
|
+
if (padLeft + padRight > maxHorizPad) {
|
|
1176
|
+
const factor = maxHorizPad / (padLeft + padRight);
|
|
1177
|
+
padLeft *= factor;
|
|
1178
|
+
padRight *= factor;
|
|
1179
|
+
}
|
|
1180
|
+
if (padTop + padBot > maxVertPad) {
|
|
1181
|
+
const factor = maxVertPad / (padTop + padBot);
|
|
1182
|
+
padTop *= factor;
|
|
1183
|
+
padBot *= factor;
|
|
1184
|
+
}
|
|
1185
|
+
try {
|
|
1186
|
+
this.map.fitBounds(this.bounds, {
|
|
1187
|
+
padding: { top: padTop, bottom: padBot, left: padLeft, right: padRight },
|
|
1188
|
+
pitch: 65,
|
|
1189
|
+
maxZoom: 12,
|
|
1190
|
+
duration: 800
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
catch (err) {
|
|
1194
|
+
console.warn('fitBounds failed, trying with default padding', err);
|
|
1195
|
+
this.map.fitBounds(this.bounds, { padding: 50, pitch: 65, maxZoom: 16 });
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
async clearAllRoutes() {
|
|
1200
|
+
// 1. Remove all markers
|
|
1201
|
+
this.markerOriginList.forEach(marker => marker.remove());
|
|
1202
|
+
this.markerDestinationList.forEach(marker => marker.remove());
|
|
1203
|
+
this.markerOriginList.clear();
|
|
1204
|
+
this.markerDestinationList.clear();
|
|
1205
|
+
// 2. Remove all arcs
|
|
1206
|
+
Object.keys(this.activeArcs).forEach(index => {
|
|
1207
|
+
const arc = this.activeArcs[index];
|
|
1208
|
+
if (arc.pathEl.parentNode)
|
|
1209
|
+
arc.pathEl.parentNode.removeChild(arc.pathEl);
|
|
1210
|
+
if (this.svgOverlay) {
|
|
1211
|
+
const grad = this.svgOverlay.querySelector(`defs #arc-grad-${index}`);
|
|
1212
|
+
if (grad && grad.parentNode)
|
|
1213
|
+
grad.parentNode.removeChild(grad);
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
this.activeArcs = {};
|
|
1217
|
+
// 3. Remove all line layers and sources using registry metadata
|
|
1218
|
+
this.activeRoutesRegistry.forEach((data, regId) => {
|
|
1219
|
+
const type = data.routeType || 'jobcode';
|
|
1220
|
+
const idx = data.index || regId.split('-').pop();
|
|
1221
|
+
const layerId = `route-layer-${type}-${idx}`;
|
|
1222
|
+
const sourceId = `route-source-${type}-${idx}`;
|
|
1223
|
+
this.map.getLayer(layerId) ? this.map.removeLayer(layerId) : null;
|
|
1224
|
+
this.map.getSource(sourceId) ? this.map.removeSource(sourceId) : null;
|
|
1225
|
+
// Legacy fallback cleanup
|
|
1226
|
+
this.map.getLayer(`line${idx}`) ? this.map.removeLayer(`line${idx}`) : null;
|
|
1227
|
+
this.map.getSource(`line${idx}`) ? this.map.removeSource(`line${idx}`) : null;
|
|
1228
|
+
this.map.getLayer(`route-for-job-code${idx}`) ? this.map.removeLayer(`route-for-job-code${idx}`) : null;
|
|
1229
|
+
this.map.getSource(`route-source-for-job-code${idx}`) ? this.map.removeSource(`route-source-for-job-code${idx}`) : null;
|
|
1230
|
+
});
|
|
1231
|
+
// 4. Reset registries and bounds
|
|
1232
|
+
this.activeRoutesRegistry.clear();
|
|
1233
|
+
this.originDestinationCordinates = [];
|
|
1234
|
+
this.bounds = new mapboxgl.LngLatBounds();
|
|
1235
|
+
if (this.popup)
|
|
1236
|
+
this.popup.remove();
|
|
1237
|
+
return true;
|
|
1057
1238
|
}
|
|
1058
1239
|
clearBound() {
|
|
1059
1240
|
this.bounds = new mapboxgl.LngLatBounds();
|
|
@@ -1061,32 +1242,24 @@ class CoolmapService {
|
|
|
1061
1242
|
this.clearPadding();
|
|
1062
1243
|
}
|
|
1063
1244
|
formateLatLong(latlong) {
|
|
1064
|
-
return latlong
|
|
1065
|
-
? latlong
|
|
1066
|
-
.split(',')
|
|
1067
|
-
.map((x) => +x)
|
|
1068
|
-
.reverse()
|
|
1069
|
-
: null;
|
|
1245
|
+
return latlong ? latlong.split(',').map((x) => +x).reverse() : null;
|
|
1070
1246
|
}
|
|
1071
1247
|
clearBoundWithCordinates() {
|
|
1072
1248
|
this.bounds = new mapboxgl.LngLatBounds();
|
|
1073
1249
|
this.originDestinationCordinates = [];
|
|
1074
1250
|
}
|
|
1075
1251
|
onResize(event) {
|
|
1076
|
-
if (!this.bounds.isEmpty()) {
|
|
1252
|
+
if (!this.bounds.isEmpty() && this.map) {
|
|
1077
1253
|
this.windowActualHeightWidth.availHeight =
|
|
1078
|
-
window.innerHeight > window.screen.availHeight
|
|
1079
|
-
? window.innerHeight
|
|
1080
|
-
: window.screen.availHeight;
|
|
1254
|
+
window.innerHeight > window.screen.availHeight ? window.innerHeight : window.screen.availHeight;
|
|
1081
1255
|
setTimeout(() => {
|
|
1256
|
+
const hRes = event.target ? event.target.innerHeight : window.innerHeight;
|
|
1082
1257
|
this.map.fitBounds(this.bounds, {
|
|
1083
1258
|
padding: {
|
|
1084
|
-
top: this.padding
|
|
1085
|
-
bottom: this.padding
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
left: this.padding.left,
|
|
1089
|
-
right: this.padding.right,
|
|
1259
|
+
top: (this.padding?.top || 0) + this.customTopForCustomer,
|
|
1260
|
+
bottom: (this.padding?.bottom || 0) + (this.windowActualHeightWidth.availHeight - (hRes - 65)),
|
|
1261
|
+
left: (this.padding?.left || 0),
|
|
1262
|
+
right: (this.padding?.right || 0),
|
|
1090
1263
|
},
|
|
1091
1264
|
pitch: 65,
|
|
1092
1265
|
});
|
|
@@ -1103,7 +1276,7 @@ class CoolmapService {
|
|
|
1103
1276
|
this.padding = null;
|
|
1104
1277
|
}
|
|
1105
1278
|
removeJobFromMap(data) {
|
|
1106
|
-
data.
|
|
1279
|
+
data.forEach((ele, index) => {
|
|
1107
1280
|
const id = ele['job_id'] ? ele['job_id'] : ele['route_id'];
|
|
1108
1281
|
this.removeRouteAndMarker(id);
|
|
1109
1282
|
if (index === data.length - 1) {
|
|
@@ -1111,24 +1284,56 @@ class CoolmapService {
|
|
|
1111
1284
|
}
|
|
1112
1285
|
});
|
|
1113
1286
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1287
|
+
resize() {
|
|
1288
|
+
if (this.map) {
|
|
1289
|
+
setTimeout(() => this.map.resize(), 0);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: MapboxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1293
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: MapboxService, providedIn: 'root' });
|
|
1116
1294
|
}
|
|
1117
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1295
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: MapboxService, decorators: [{
|
|
1118
1296
|
type: Injectable,
|
|
1119
|
-
args: [{
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1297
|
+
args: [{
|
|
1298
|
+
providedIn: 'root'
|
|
1299
|
+
}]
|
|
1300
|
+
}], ctorParameters: () => [] });
|
|
1301
|
+
|
|
1302
|
+
class CoolmapService {
|
|
1303
|
+
mapbox = inject(MapboxService);
|
|
1304
|
+
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1305
|
+
plottingIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "plottingIds" }] : []));
|
|
1306
|
+
plotRoute(route, i, type = 'jobcode', enablefitbound, showAllFitbound) {
|
|
1307
|
+
if (!route)
|
|
1308
|
+
return;
|
|
1309
|
+
return this.mapbox.plotRoute(route, i, type, enablefitbound, showAllFitbound);
|
|
1310
|
+
}
|
|
1311
|
+
loadMapProperty(pinRouteGeojson, index, unit, routeProps) {
|
|
1312
|
+
this.mapbox.loadMapProperty(pinRouteGeojson, index, unit, routeProps);
|
|
1313
|
+
}
|
|
1314
|
+
removeRouteAndMarker(index, type = 'jobcode') {
|
|
1315
|
+
return this.mapbox.removeRouteAndMarker(index, type);
|
|
1316
|
+
}
|
|
1317
|
+
clearAllRoutes() {
|
|
1318
|
+
return this.mapbox.clearAllRoutes();
|
|
1319
|
+
}
|
|
1320
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1321
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapService, providedIn: 'root' });
|
|
1322
|
+
}
|
|
1323
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapService, decorators: [{
|
|
1324
|
+
type: Injectable,
|
|
1325
|
+
args: [{
|
|
1326
|
+
providedIn: 'root'
|
|
1327
|
+
}]
|
|
1328
|
+
}] });
|
|
1124
1329
|
|
|
1125
1330
|
/*
|
|
1126
|
-
* Public API Surface of
|
|
1331
|
+
* Public API Surface of coolmap-services
|
|
1127
1332
|
*/
|
|
1128
1333
|
|
|
1129
1334
|
/**
|
|
1130
1335
|
* Generated bundle index. Do not edit.
|
|
1131
1336
|
*/
|
|
1132
1337
|
|
|
1133
|
-
export {
|
|
1338
|
+
export { COOLMAP_CONFIG, CoolmapService, CoolmapServices, MapboxService, UtilsService, provideCoolmapConfig };
|
|
1134
1339
|
//# sourceMappingURL=aggdirect-coolmap-services.mjs.map
|