becomap 1.6.0 → 1.6.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.
@@ -0,0 +1,500 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
7
+ <title>Becomap UMD SDK</title>
8
+ <style>
9
+ body,
10
+ html {
11
+ margin: 0;
12
+ padding: 0;
13
+ height: 100%;
14
+ }
15
+
16
+ #mapContainer {
17
+ width: 100%;
18
+ height: 100%;
19
+ }
20
+ </style>
21
+ </head>
22
+
23
+ <body>
24
+ <div id="mapContainer"></div>
25
+
26
+ <!-- External libs -->
27
+ <script src="https://unpkg.com/maplibre-gl@4.4.1/dist/maplibre-gl.js"></script>
28
+ <script src="https://unpkg.com/@turf/turf@7.1.0/turf.min.js"></script>
29
+
30
+ <!-- Core Map SDK Integration -->
31
+ <script>
32
+ // ============================================================================
33
+ // GLOBAL VARIABLES
34
+ // ============================================================================
35
+ window._mapView = null;
36
+ window._site = null;
37
+ window._eventListeners = new Map();
38
+
39
+ // ============================================================================
40
+ // UTILITY FUNCTIONS
41
+ // ============================================================================
42
+
43
+ /**
44
+ * Sends messages to native platform (iOS/Android)
45
+ * @param {string} type - Message type
46
+ * @param {any} payload - Message payload
47
+ */
48
+ function notifyNative(type, payload = null) {
49
+ const message = JSON.stringify({ type, payload });
50
+
51
+ if (window.webkit?.messageHandlers?.jsHandler) {
52
+ // iOS
53
+ window.webkit.messageHandlers.jsHandler.postMessage(message);
54
+ } else if (window.jsHandler?.postMessage) {
55
+ // Android
56
+ window.jsHandler.postMessage(message);
57
+ } else {
58
+ console.log("Native handler not available:", message);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Safely converts objects to JSON with error handling
64
+ * @param {any} obj - Object to convert
65
+ * @returns {any} - JSON object or original object if conversion fails
66
+ */
67
+ function safeToJSON(obj) {
68
+ try {
69
+ return obj?.toJSON ? obj.toJSON() : obj;
70
+ } catch (error) {
71
+ console.warn('Error converting to JSON:', error);
72
+ return obj;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Executes function with error handling and native notification
78
+ * @param {Function} fn - Function to execute
79
+ * @param {string} errorType - Error type for native notification
80
+ * @param {any} fallbackValue - Fallback value if function fails
81
+ */
82
+ function executeWithErrorHandling(fn, errorType, fallbackValue = null) {
83
+ try {
84
+ const result = fn();
85
+ return result !== undefined ? result : fallbackValue;
86
+ } catch (error) {
87
+ console.error(`${errorType} error:`, error);
88
+ notifyNative(errorType, { message: error.message });
89
+ return fallbackValue;
90
+ }
91
+ }
92
+
93
+ // ============================================================================
94
+ // BCMapViewEvents CALLBACKS
95
+ // ============================================================================
96
+
97
+ /**
98
+ * Sets up event listeners for BCMapViewEvents
99
+ * @param {Object} mapView - The map view instance
100
+ */
101
+ function setupMapViewEventListeners(mapView) {
102
+ if (!mapView || !mapView.eventsHandler) {
103
+ console.warn('MapView does not support event listeners');
104
+ return;
105
+ }
106
+
107
+ // Clear existing listeners
108
+ clearMapViewEventListeners();
109
+
110
+ // Map load event
111
+ const loadListenerId = mapView.eventsHandler.on('load', () => {
112
+ notifyNative("mapLoad", { timestamp: Date.now() });
113
+ });
114
+
115
+ // View change event
116
+ const viewChangeListenerId = mapView.eventsHandler.on('viewChange', (args) => {
117
+ notifyNative("viewChange", {
118
+ viewOptions: safeToJSON(args.viewOptions),
119
+ timestamp: Date.now()
120
+ });
121
+ });
122
+
123
+ // Location selection event
124
+ const selectListenerId = mapView.eventsHandler.on('select', (args) => {
125
+ notifyNative("locationSelect", {
126
+ locations: args.locations?.map(loc => safeToJSON(loc)) || [],
127
+ timestamp: Date.now()
128
+ });
129
+ });
130
+
131
+ // Floor switch event
132
+ const switchToFloorListenerId = mapView.eventsHandler.on('switchToFloor', (args) => {
133
+ notifyNative("floorSwitch", {
134
+ floor: safeToJSON(args.floor),
135
+ timestamp: Date.now()
136
+ });
137
+ });
138
+
139
+ // Route step load event
140
+ const stepLoadListenerId = mapView.eventsHandler.on('stepLoad', (args) => {
141
+ notifyNative("stepLoad", {
142
+ step: safeToJSON(args.step),
143
+ timestamp: Date.now()
144
+ });
145
+ });
146
+
147
+ // Walkthrough end event
148
+ const walkthroughEndListenerId = mapView.eventsHandler.on('walkthroughEnd', () => {
149
+ notifyNative("walkthroughEnd", { timestamp: Date.now() });
150
+ });
151
+
152
+ // Store listener IDs for cleanup
153
+ window._eventListeners.set('load', loadListenerId);
154
+ window._eventListeners.set('viewChange', viewChangeListenerId);
155
+ window._eventListeners.set('select', selectListenerId);
156
+ window._eventListeners.set('switchToFloor', switchToFloorListenerId);
157
+ window._eventListeners.set('stepLoad', stepLoadListenerId);
158
+ window._eventListeners.set('walkthroughEnd', walkthroughEndListenerId);
159
+ }
160
+
161
+ /**
162
+ * Clears all map view event listeners
163
+ */
164
+ function clearMapViewEventListeners() {
165
+ if (!window._mapView || !window._mapView.eventsHandler) {
166
+ return;
167
+ }
168
+
169
+ window._eventListeners.forEach((listenerId, eventName) => {
170
+ try {
171
+ window._mapView.eventsHandler.off(eventName, listenerId);
172
+ } catch (error) {
173
+ console.warn(`Error removing ${eventName} listener:`, error);
174
+ }
175
+ });
176
+
177
+ window._eventListeners.clear();
178
+ }
179
+
180
+ // ============================================================================
181
+ // INITIALIZATION
182
+ // ============================================================================
183
+
184
+ /**
185
+ * Initializes the map with site options
186
+ * @param {Object} siteOptions - Site configuration options
187
+ */
188
+ async function init(siteOptions) {
189
+ try {
190
+ const container = document.getElementById('mapContainer');
191
+ if (!container) {
192
+ throw new Error('Map container not found');
193
+ }
194
+
195
+ if (!window.becomap?.getSite || !window.becomap?.getMapView) {
196
+ throw new Error('Becomap UMD not loaded');
197
+ }
198
+
199
+ const mapOptions = { zoom: 18.5 };
200
+ window._site = await window.becomap.getSite(siteOptions);
201
+ window._mapView = await window.becomap.getMapView(container, window._site, mapOptions);
202
+
203
+ // Setup event listeners
204
+ setupMapViewEventListeners(window._mapView);
205
+
206
+ notifyNative("onRenderComplete", {
207
+ site: safeToJSON(window._site),
208
+ timestamp: Date.now()
209
+ });
210
+ } catch (err) {
211
+ console.error('Init error:', err);
212
+ notifyNative("initError", {
213
+ message: err.message,
214
+ timestamp: Date.now()
215
+ });
216
+ }
217
+ }
218
+
219
+ // ============================================================================
220
+ // MAP VIEW METHODS
221
+ // ============================================================================
222
+
223
+ // Floor and Location Methods
224
+ globalThis.getCurrentFloor = () => {
225
+ const floor = executeWithErrorHandling(
226
+ () => window._mapView?.currentFloor,
227
+ "getCurrentFloorError"
228
+ );
229
+ notifyNative("getCurrentFloor", safeToJSON(floor));
230
+ };
231
+
232
+ globalThis.selectFloorWithId = (floor) => {
233
+ executeWithErrorHandling(
234
+ () => window._mapView?.selectFloorWithId(floor),
235
+ "selectFloorError"
236
+ );
237
+ };
238
+
239
+ globalThis.selectLocationWithId = (location) => {
240
+ executeWithErrorHandling(
241
+ () => window._mapView?.selectLocationWithId(location),
242
+ "selectLocationError"
243
+ );
244
+ };
245
+
246
+ // Data Retrieval Methods
247
+ globalThis.getCategories = () => {
248
+ const categories = executeWithErrorHandling(
249
+ () => window._mapView?.getCategories(),
250
+ "getCategoriesError",
251
+ []
252
+ );
253
+ notifyNative("getCategories", categories?.map(cat => safeToJSON(cat)) || []);
254
+ };
255
+
256
+ globalThis.getLocations = () => {
257
+ const locations = executeWithErrorHandling(
258
+ () => window._mapView?.getLocations(),
259
+ "getLocationsError",
260
+ []
261
+ );
262
+ notifyNative("getLocations", locations?.map(loc => safeToJSON(loc)) || []);
263
+ };
264
+
265
+ globalThis.getAllAmenities = () => {
266
+ const amenities = executeWithErrorHandling(
267
+ () => window._mapView?.getAllAminityLocations(),
268
+ "getAllAmenitiesError",
269
+ []
270
+ );
271
+ notifyNative("getAllAmenities", amenities?.map(amenity => safeToJSON(amenity)) || []);
272
+ };
273
+
274
+ globalThis.getAmenities = () => {
275
+ const amenities = executeWithErrorHandling(
276
+ () => window._mapView?.getAmenities(),
277
+ "getAmenitiesError",
278
+ []
279
+ );
280
+ notifyNative("getAmenities", amenities?.map(amenity => safeToJSON(amenity)) || []);
281
+ };
282
+
283
+ globalThis.selectAmenities = (type) => {
284
+ executeWithErrorHandling(
285
+ () => window._mapView?.selectAmenities(type),
286
+ "selectAmenitiesError"
287
+ );
288
+ };
289
+
290
+ // Session and Event Methods
291
+ globalThis.getSessionId = async () => {
292
+ try {
293
+ const sessionId = await window._mapView?.getSessionId();
294
+ notifyNative("getSessionId", sessionId);
295
+ } catch (err) {
296
+ notifyNative("getSessionIdError", {
297
+ message: err.message,
298
+ timestamp: Date.now()
299
+ });
300
+ }
301
+ };
302
+
303
+ globalThis.getQuestions = () => {
304
+ const questions = executeWithErrorHandling(
305
+ () => window._mapView?.getQuestions(),
306
+ "getQuestionsError",
307
+ []
308
+ );
309
+ notifyNative("getQuestions", questions?.map(q => safeToJSON(q)) || []);
310
+ };
311
+
312
+ globalThis.getHappenings = (type) => {
313
+ const happenings = executeWithErrorHandling(
314
+ () => window._mapView?.getHappenings(type),
315
+ "getHappeningsError",
316
+ []
317
+ );
318
+ notifyNative("getHappenings", happenings?.map(h => safeToJSON(h)) || []);
319
+ };
320
+
321
+ globalThis.getEventSuggestions = async (sessionId, answers) => {
322
+ try {
323
+ const suggestions = await window._mapView?.getEventSuggestions(sessionId, answers);
324
+ notifyNative("getEventSuggestions", suggestions?.map(s => safeToJSON(s)) || []);
325
+ } catch (err) {
326
+ notifyNative("getEventSuggestionsError", {
327
+ message: err.message,
328
+ timestamp: Date.now()
329
+ });
330
+ }
331
+ };
332
+
333
+ // Viewport and Camera Methods
334
+ globalThis.focusTo = (location, zoom, bearing, pitch) => {
335
+ executeWithErrorHandling(
336
+ () => window._mapView?.focusTo(location, zoom, bearing, pitch),
337
+ "focusToError"
338
+ );
339
+ };
340
+
341
+ globalThis.clearSelection = () => {
342
+ executeWithErrorHandling(
343
+ () => window._mapView?.clearSelection(),
344
+ "clearSelectionError"
345
+ );
346
+ };
347
+
348
+ globalThis.updateZoom = (zoom) => {
349
+ executeWithErrorHandling(
350
+ () => window._mapView?.updateZoom(zoom),
351
+ "updateZoomError"
352
+ );
353
+ };
354
+
355
+ globalThis.updatePitch = (pitch) => {
356
+ executeWithErrorHandling(
357
+ () => window._mapView?.updatePitch(pitch),
358
+ "updatePitchError"
359
+ );
360
+ };
361
+
362
+ globalThis.updateBearing = (bearing) => {
363
+ executeWithErrorHandling(
364
+ () => window._mapView?.updateBearing(bearing),
365
+ "updateBearingError"
366
+ );
367
+ };
368
+
369
+ globalThis.enableMultiSelection = (val) => {
370
+ executeWithErrorHandling(
371
+ () => window._mapView?.enableMultiSelection(val),
372
+ "enableMultiSelectionError"
373
+ );
374
+ };
375
+
376
+ globalThis.setBounds = (sw, ne) => {
377
+ executeWithErrorHandling(
378
+ () => window._mapView?.setBounds(sw, ne),
379
+ "setBoundsError"
380
+ );
381
+ };
382
+
383
+ globalThis.setViewport = (options) => {
384
+ executeWithErrorHandling(
385
+ () => window._mapView?.setViewport(options),
386
+ "setViewportError"
387
+ );
388
+ };
389
+
390
+ globalThis.resetDefaultViewport = (options) => {
391
+ executeWithErrorHandling(
392
+ () => window._mapView?.resetDefaultViewport(options),
393
+ "resetDefaultViewportError"
394
+ );
395
+ };
396
+
397
+ // Search Methods
398
+ globalThis.searchForLocations = (q, callbackId) => {
399
+ if (!window._mapView?.searchForLocations) {
400
+ notifyNative("searchForLocations", {
401
+ callbackId,
402
+ results: [],
403
+ error: "Search method not available"
404
+ });
405
+ return;
406
+ }
407
+
408
+ window._mapView.searchForLocations(q, (matches) => {
409
+ notifyNative("searchForLocations", {
410
+ callbackId,
411
+ results: matches?.map(m => safeToJSON(m)) || []
412
+ });
413
+ });
414
+ };
415
+
416
+ globalThis.searchForCategories = (q, callbackId) => {
417
+ if (!window._mapView?.searchForCategories) {
418
+ notifyNative("searchForCategories", {
419
+ callbackId,
420
+ results: [],
421
+ error: "Search method not available"
422
+ });
423
+ return;
424
+ }
425
+
426
+ window._mapView.searchForCategories(q, (matches) => {
427
+ notifyNative("searchForCategories", {
428
+ callbackId,
429
+ results: matches?.map(m => safeToJSON(m)) || []
430
+ });
431
+ });
432
+ };
433
+
434
+ // ============================================================================
435
+ // ROUTE CONTROLLER METHODS
436
+ // ============================================================================
437
+
438
+ globalThis.getRoute = (startID, goalID, waypoints = [], routeOptions) => {
439
+ try {
440
+ const routes = window.becomap.getRouteById(startID, goalID, waypoints, routeOptions);
441
+ notifyNative("getRoute", routes?.map(route => safeToJSON(route)) || []);
442
+ } catch (error) {
443
+ notifyNative("getRouteError", {
444
+ message: error.message,
445
+ timestamp: Date.now()
446
+ });
447
+ }
448
+ };
449
+
450
+ globalThis.showRoute = () => {
451
+ executeWithErrorHandling(
452
+ () => window._mapView?.routeController?.showSavedRoute(),
453
+ "showRouteError"
454
+ );
455
+ };
456
+
457
+ globalThis.showStep = (step) => {
458
+ executeWithErrorHandling(
459
+ () => window._mapView?.routeController?.showStepByOrderIndex(step),
460
+ "showStepError"
461
+ );
462
+ };
463
+
464
+ globalThis.clearAllRoutes = () => {
465
+ executeWithErrorHandling(
466
+ () => window._mapView?.routeController?.clearAllRoutes(),
467
+ "clearAllRoutesError"
468
+ );
469
+ };
470
+
471
+ // ============================================================================
472
+ // CLEANUP AND EXPORTS
473
+ // ============================================================================
474
+
475
+ /**
476
+ * Cleanup function to be called when the webview is destroyed
477
+ */
478
+ globalThis.cleanup = () => {
479
+ clearMapViewEventListeners();
480
+ window._mapView = null;
481
+ window._site = null;
482
+ };
483
+
484
+ // Export init function
485
+ globalThis.init = init;
486
+ </script>
487
+
488
+ <!-- <script>
489
+ const siteOptions = {
490
+ clientId: "c079dfa3a77dad13351cfacd95841c2c2780fe08",
491
+ clientSecret: "f62a59675b2a47ddb75f1f994d88e653",
492
+ siteIdentifier: "67dcf5dd2f21c64e3225254f"
493
+ };
494
+ window.addEventListener("DOMContentLoaded", () => {
495
+ init(siteOptions);
496
+ });
497
+ </script> -->
498
+ </body>
499
+
500
+ </html>
@@ -0,0 +1,91 @@
1
+ const path = require('path');
2
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
3
+ const WebpackObfuscator = require('webpack-obfuscator');
4
+ const TerserPlugin = require('terser-webpack-plugin');
5
+ const Dotenv = require('dotenv-webpack');
6
+
7
+ const envFile = `.env`;
8
+
9
+ module.exports = {
10
+ mode: 'production',
11
+ entry: './src/index.ts',
12
+ output: {
13
+ filename: 'becomap.[contenthash].js',
14
+ chunkFilename: 'becomap.[name].[contenthash].js',
15
+ path: path.resolve(__dirname, 'esm-build'),
16
+ library: 'becomap',
17
+ libraryTarget: 'umd',
18
+ umdNamedDefine: true,
19
+ globalObject: 'this',
20
+ },
21
+ resolve: {
22
+ extensions: ['.ts', '.js'],
23
+ },
24
+ module: {
25
+ rules: [
26
+ {
27
+ test: /\.ts$/,
28
+ use: 'ts-loader',
29
+ exclude: /node_modules/,
30
+ },
31
+ {
32
+ test: /\.css$/,
33
+ use: ['style-loader', 'css-loader'],
34
+ },
35
+ {
36
+ test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
37
+ type: 'asset',
38
+ },
39
+ ],
40
+ },
41
+ optimization: {
42
+ minimize: true,
43
+ minimizer: [
44
+ new TerserPlugin({
45
+ terserOptions: {
46
+ compress: {
47
+ drop_console: false,
48
+ },
49
+ },
50
+ }),
51
+ ],
52
+ splitChunks : {
53
+ chunks: 'all',
54
+ minSize: 30000,
55
+ maxSize: 204800,
56
+ cacheGroups: {
57
+ vendors: {
58
+ test: /[\\/]node_modules[\\/]/,
59
+ name: 'vendors',
60
+ enforce: true,
61
+ priority: -10,
62
+ },
63
+ default: {
64
+ minChunks: 2,
65
+ priority: -20,
66
+ reuseExistingChunk: true,
67
+ },
68
+ }
69
+ },
70
+ runtimeChunk: 'single'
71
+ },
72
+ externalsType: 'window',
73
+ externals: {
74
+ 'maplibre-gl': 'maplibregl',
75
+ '@turf/turf': 'turf'
76
+ },
77
+ plugins: [
78
+ new Dotenv({
79
+ path: envFile,
80
+ }),
81
+ new HtmlWebpackPlugin({
82
+ template: './public/index.html',
83
+ filename: 'index.html',
84
+ inject: 'body',
85
+ }),
86
+ new WebpackObfuscator(
87
+ { stringArray: false },
88
+ ['node_modules/**/*']
89
+ ),
90
+ ],
91
+ };