gistda-sphere-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +827 -0
  2. package/dist/index.d.mts +1081 -0
  3. package/dist/index.d.ts +1081 -0
  4. package/dist/index.js +2057 -0
  5. package/dist/index.mjs +2013 -0
  6. package/package.json +70 -0
  7. package/src/__tests__/Layer.test.tsx +133 -0
  8. package/src/__tests__/Marker.test.tsx +183 -0
  9. package/src/__tests__/SphereContext.test.tsx +120 -0
  10. package/src/__tests__/SphereMap.test.tsx +240 -0
  11. package/src/__tests__/geometry.test.tsx +454 -0
  12. package/src/__tests__/hooks.test.tsx +173 -0
  13. package/src/__tests__/setup.ts +204 -0
  14. package/src/__tests__/useMapControls.test.tsx +168 -0
  15. package/src/__tests__/useOverlays.test.tsx +265 -0
  16. package/src/__tests__/useRoute.test.tsx +219 -0
  17. package/src/__tests__/useSearch.test.tsx +205 -0
  18. package/src/__tests__/useTags.test.tsx +179 -0
  19. package/src/components/Circle.tsx +189 -0
  20. package/src/components/Dot.tsx +150 -0
  21. package/src/components/Layer.tsx +177 -0
  22. package/src/components/Marker.tsx +204 -0
  23. package/src/components/Polygon.tsx +223 -0
  24. package/src/components/Polyline.tsx +211 -0
  25. package/src/components/Popup.tsx +130 -0
  26. package/src/components/Rectangle.tsx +194 -0
  27. package/src/components/SphereMap.tsx +315 -0
  28. package/src/components/index.ts +18 -0
  29. package/src/context/MapContext.tsx +41 -0
  30. package/src/context/SphereContext.tsx +348 -0
  31. package/src/context/index.ts +15 -0
  32. package/src/hooks/index.ts +42 -0
  33. package/src/hooks/useMapEvent.ts +66 -0
  34. package/src/hooks/useOverlays.ts +278 -0
  35. package/src/hooks/useRoute.ts +232 -0
  36. package/src/hooks/useSearch.ts +143 -0
  37. package/src/hooks/useSphere.ts +18 -0
  38. package/src/hooks/useTags.ts +129 -0
  39. package/src/index.ts +124 -0
  40. package/src/types/index.ts +1 -0
  41. package/src/types/sphere.ts +671 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,2013 @@
1
+ // src/components/Circle.tsx
2
+ import { forwardRef, useEffect as useEffect2, useImperativeHandle, useRef as useRef2 } from "react";
3
+
4
+ // src/context/MapContext.tsx
5
+ import { createContext, useContext, useMemo } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ var MapContext = createContext(null);
8
+ function MapProvider({
9
+ map,
10
+ isReady,
11
+ children
12
+ }) {
13
+ const value = useMemo(
14
+ () => ({ map, isReady }),
15
+ [map, isReady]
16
+ );
17
+ return /* @__PURE__ */ jsx(MapContext.Provider, { value, children });
18
+ }
19
+ function useMapContext() {
20
+ const context = useContext(MapContext);
21
+ if (!context) {
22
+ throw new Error("useMapContext must be used within a SphereMap component");
23
+ }
24
+ return context;
25
+ }
26
+
27
+ // src/context/SphereContext.tsx
28
+ import {
29
+ createContext as createContext2,
30
+ useCallback,
31
+ useContext as useContext2,
32
+ useEffect,
33
+ useMemo as useMemo2,
34
+ useRef,
35
+ useState
36
+ } from "react";
37
+ import { jsx as jsx2 } from "react/jsx-runtime";
38
+ var SphereContext = createContext2(null);
39
+ var SCRIPT_ID = "gistda-sphere-api-script";
40
+ var scriptLoadingPromise = null;
41
+ function loadSphereScript(apiKey, customUrl) {
42
+ if (scriptLoadingPromise) {
43
+ return scriptLoadingPromise;
44
+ }
45
+ const existingScript = document.getElementById(SCRIPT_ID);
46
+ if (existingScript) {
47
+ if (window.sphere) {
48
+ return Promise.resolve();
49
+ }
50
+ existingScript.remove();
51
+ }
52
+ scriptLoadingPromise = new Promise((resolve, reject) => {
53
+ const script = document.createElement("script");
54
+ script.id = SCRIPT_ID;
55
+ script.type = "text/javascript";
56
+ script.src = customUrl || `https://api.sphere.gistda.or.th/map/?key=${apiKey}`;
57
+ script.async = true;
58
+ script.onload = () => {
59
+ setTimeout(() => {
60
+ if (window.sphere) {
61
+ resolve();
62
+ } else {
63
+ reject(
64
+ new Error("Sphere API loaded but window.sphere is not available")
65
+ );
66
+ }
67
+ }, 0);
68
+ };
69
+ script.onerror = () => {
70
+ script.remove();
71
+ scriptLoadingPromise = null;
72
+ reject(
73
+ new Error(
74
+ "Failed to load Sphere API script. This may be due to domain restrictions. Ensure your API key is registered for your domain at https://sphere.gistda.or.th/"
75
+ )
76
+ );
77
+ };
78
+ document.head.appendChild(script);
79
+ });
80
+ return scriptLoadingPromise;
81
+ }
82
+ function SphereProvider({
83
+ apiKey,
84
+ children,
85
+ scriptUrl,
86
+ onLoad,
87
+ onError
88
+ }) {
89
+ const [isLoaded, setIsLoaded] = useState(false);
90
+ const [error, setError] = useState(null);
91
+ const [sphere, setSphere] = useState(null);
92
+ const [map, setMap] = useState(null);
93
+ const [isMapReady, setIsMapReady] = useState(false);
94
+ const mapRef = useRef(null);
95
+ const handleLoad = useCallback(() => {
96
+ setIsLoaded(true);
97
+ setSphere(window.sphere ?? null);
98
+ onLoad?.();
99
+ }, [onLoad]);
100
+ const handleError = useCallback(
101
+ (err) => {
102
+ setError(err);
103
+ onError?.(err);
104
+ },
105
+ [onError]
106
+ );
107
+ useEffect(() => {
108
+ if (window.sphere) {
109
+ handleLoad();
110
+ return;
111
+ }
112
+ loadSphereScript(apiKey, scriptUrl).then(handleLoad).catch(handleError);
113
+ }, [apiKey, scriptUrl, handleLoad, handleError]);
114
+ const registerMap = useCallback((newMap) => {
115
+ mapRef.current = newMap;
116
+ setMap(newMap);
117
+ setIsMapReady(true);
118
+ }, []);
119
+ const unregisterMap = useCallback(() => {
120
+ mapRef.current = null;
121
+ setMap(null);
122
+ setIsMapReady(false);
123
+ }, []);
124
+ const goTo = useCallback((options, animate = true) => {
125
+ mapRef.current?.goTo(options, animate);
126
+ }, []);
127
+ const setCenter = useCallback((location, animate = true) => {
128
+ mapRef.current?.location(location, animate);
129
+ }, []);
130
+ const setZoom = useCallback((zoom, animate = true) => {
131
+ mapRef.current?.zoom(zoom, animate);
132
+ }, []);
133
+ const setBound = useCallback((bound, options) => {
134
+ mapRef.current?.bound(bound, options);
135
+ }, []);
136
+ const setRotate = useCallback((angle, animate = true) => {
137
+ mapRef.current?.rotate(angle, animate);
138
+ }, []);
139
+ const setPitch = useCallback((angle) => {
140
+ mapRef.current?.pitch(angle);
141
+ }, []);
142
+ const setFilter = useCallback((filter) => {
143
+ if (mapRef.current && window.sphere) {
144
+ const filterValue = filter === false ? false : window.sphere.Filter[filter];
145
+ mapRef.current.enableFilter(filterValue);
146
+ }
147
+ }, []);
148
+ const setLanguage = useCallback((language) => {
149
+ mapRef.current?.language(language);
150
+ }, []);
151
+ const resize = useCallback(() => {
152
+ mapRef.current?.resize();
153
+ }, []);
154
+ const repaint = useCallback(() => {
155
+ mapRef.current?.repaint();
156
+ }, []);
157
+ const setBaseLayer = useCallback((layer) => {
158
+ const layerValue = window.sphere?.Layers?.[layer];
159
+ if (mapRef.current && layerValue) {
160
+ mapRef.current.Layers.setBase(layerValue);
161
+ }
162
+ }, []);
163
+ const addLayer = useCallback((layer) => {
164
+ const layerValue = window.sphere?.Layers?.[layer];
165
+ if (mapRef.current && layerValue) {
166
+ mapRef.current.Layers.add(layerValue);
167
+ }
168
+ }, []);
169
+ const removeLayer = useCallback((layer) => {
170
+ const layerValue = window.sphere?.Layers?.[layer];
171
+ if (mapRef.current && layerValue) {
172
+ mapRef.current.Layers.remove(layerValue);
173
+ }
174
+ }, []);
175
+ const controls = useMemo2(
176
+ () => ({
177
+ isReady: isMapReady && sphere !== null,
178
+ goTo,
179
+ setCenter,
180
+ setZoom,
181
+ setBound,
182
+ setRotate,
183
+ setPitch,
184
+ setFilter,
185
+ setLanguage,
186
+ setBaseLayer,
187
+ addLayer,
188
+ removeLayer,
189
+ resize,
190
+ repaint
191
+ }),
192
+ [
193
+ isMapReady,
194
+ sphere,
195
+ goTo,
196
+ setCenter,
197
+ setZoom,
198
+ setBound,
199
+ setRotate,
200
+ setPitch,
201
+ setFilter,
202
+ setLanguage,
203
+ setBaseLayer,
204
+ addLayer,
205
+ removeLayer,
206
+ resize,
207
+ repaint
208
+ ]
209
+ );
210
+ const contextValue = useMemo2(
211
+ () => ({
212
+ isLoaded,
213
+ error,
214
+ sphere,
215
+ apiKey,
216
+ map,
217
+ isMapReady,
218
+ controls,
219
+ registerMap,
220
+ unregisterMap
221
+ }),
222
+ [
223
+ isLoaded,
224
+ error,
225
+ sphere,
226
+ apiKey,
227
+ map,
228
+ isMapReady,
229
+ controls,
230
+ registerMap,
231
+ unregisterMap
232
+ ]
233
+ );
234
+ return /* @__PURE__ */ jsx2(SphereContext.Provider, { value: contextValue, children });
235
+ }
236
+ function useSphereContext() {
237
+ const context = useContext2(SphereContext);
238
+ if (!context) {
239
+ throw new Error("useSphereContext must be used within a SphereProvider");
240
+ }
241
+ return context;
242
+ }
243
+ function useMap() {
244
+ const { map, isMapReady, sphere } = useSphereContext();
245
+ return { map, sphere, isReady: isMapReady && sphere !== null };
246
+ }
247
+ function useMapControls() {
248
+ const { controls } = useSphereContext();
249
+ return controls;
250
+ }
251
+
252
+ // src/components/Circle.tsx
253
+ var Circle = forwardRef(function Circle2({
254
+ center,
255
+ radius,
256
+ title,
257
+ detail,
258
+ popup,
259
+ visibleRange,
260
+ lineWidth,
261
+ lineColor,
262
+ fillColor,
263
+ lineStyle,
264
+ clickable,
265
+ draggable,
266
+ zIndex,
267
+ onClick,
268
+ onDrag,
269
+ onDrop
270
+ }, ref) {
271
+ const { map, isReady } = useMapContext();
272
+ const { sphere } = useSphereContext();
273
+ const circleRef = useRef2(null);
274
+ const callbacksRef = useRef2({ onClick, onDrag, onDrop });
275
+ useEffect2(() => {
276
+ callbacksRef.current = { onClick, onDrag, onDrop };
277
+ }, [onClick, onDrag, onDrop]);
278
+ useEffect2(() => {
279
+ if (!(isReady && map && sphere)) {
280
+ return;
281
+ }
282
+ const options = {};
283
+ if (title) {
284
+ options.title = title;
285
+ }
286
+ if (detail) {
287
+ options.detail = detail;
288
+ }
289
+ if (popup) {
290
+ options.popup = popup;
291
+ }
292
+ if (visibleRange) {
293
+ options.visibleRange = visibleRange;
294
+ }
295
+ if (typeof lineWidth === "number") {
296
+ options.lineWidth = lineWidth;
297
+ }
298
+ if (lineColor) {
299
+ options.lineColor = lineColor;
300
+ }
301
+ if (fillColor) {
302
+ options.fillColor = fillColor;
303
+ }
304
+ if (lineStyle) {
305
+ options.lineStyle = lineStyle;
306
+ }
307
+ if (typeof clickable === "boolean") {
308
+ options.clickable = clickable;
309
+ }
310
+ if (typeof draggable === "boolean") {
311
+ options.draggable = draggable;
312
+ }
313
+ if (typeof zIndex === "number") {
314
+ options.zIndex = zIndex;
315
+ }
316
+ const circle = new sphere.Circle(center, radius, options);
317
+ circleRef.current = circle;
318
+ map.Overlays.add(circle);
319
+ const handleOverlayClick = (data) => {
320
+ if (data.overlay === circle) {
321
+ callbacksRef.current.onClick?.(circle);
322
+ }
323
+ };
324
+ const handleOverlayDrag = (overlay) => {
325
+ if (overlay === circle) {
326
+ callbacksRef.current.onDrag?.(circle);
327
+ }
328
+ };
329
+ const handleOverlayDrop = (overlay) => {
330
+ if (overlay === circle) {
331
+ callbacksRef.current.onDrop?.(circle);
332
+ }
333
+ };
334
+ map.Event.bind("overlayClick", handleOverlayClick);
335
+ map.Event.bind("overlayDrag", handleOverlayDrag);
336
+ map.Event.bind("overlayDrop", handleOverlayDrop);
337
+ return () => {
338
+ map.Event.unbind("overlayClick", handleOverlayClick);
339
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
340
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
341
+ map.Overlays.remove(circle);
342
+ circleRef.current = null;
343
+ };
344
+ }, [
345
+ isReady,
346
+ map,
347
+ sphere,
348
+ center,
349
+ radius,
350
+ title,
351
+ detail,
352
+ popup,
353
+ visibleRange,
354
+ lineWidth,
355
+ lineColor,
356
+ fillColor,
357
+ lineStyle,
358
+ clickable,
359
+ draggable,
360
+ zIndex
361
+ ]);
362
+ useImperativeHandle(
363
+ ref,
364
+ () => ({
365
+ getCircle: () => circleRef.current,
366
+ togglePopup: (show, location) => {
367
+ circleRef.current?.pop(show, location);
368
+ },
369
+ getCenter: () => circleRef.current?.location() ?? null,
370
+ getBound: () => circleRef.current?.bound() ?? null,
371
+ getArea: (language) => circleRef.current?.size(language) ?? null,
372
+ getRadius: (language) => circleRef.current?.radius(language) ?? null,
373
+ updateStyle: (options) => {
374
+ circleRef.current?.update(options);
375
+ }
376
+ }),
377
+ []
378
+ );
379
+ return null;
380
+ });
381
+
382
+ // src/components/Dot.tsx
383
+ import { forwardRef as forwardRef2, useEffect as useEffect3, useImperativeHandle as useImperativeHandle2, useRef as useRef3 } from "react";
384
+ var Dot = forwardRef2(function Dot2({
385
+ position,
386
+ title,
387
+ detail,
388
+ visibleRange,
389
+ lineWidth,
390
+ lineColor,
391
+ clickable,
392
+ draggable,
393
+ zIndex,
394
+ onClick,
395
+ onDrag,
396
+ onDrop
397
+ }, ref) {
398
+ const { map, isReady } = useMapContext();
399
+ const { sphere } = useSphereContext();
400
+ const dotRef = useRef3(null);
401
+ const callbacksRef = useRef3({ onClick, onDrag, onDrop });
402
+ useEffect3(() => {
403
+ callbacksRef.current = { onClick, onDrag, onDrop };
404
+ }, [onClick, onDrag, onDrop]);
405
+ useEffect3(() => {
406
+ if (!(isReady && map && sphere)) {
407
+ return;
408
+ }
409
+ const options = {};
410
+ if (title) {
411
+ options.title = title;
412
+ }
413
+ if (detail) {
414
+ options.detail = detail;
415
+ }
416
+ if (visibleRange) {
417
+ options.visibleRange = visibleRange;
418
+ }
419
+ if (typeof lineWidth === "number") {
420
+ options.lineWidth = lineWidth;
421
+ }
422
+ if (lineColor) {
423
+ options.lineColor = lineColor;
424
+ }
425
+ if (typeof clickable === "boolean") {
426
+ options.clickable = clickable;
427
+ }
428
+ if (typeof draggable === "boolean") {
429
+ options.draggable = draggable;
430
+ }
431
+ if (typeof zIndex === "number") {
432
+ options.zIndex = zIndex;
433
+ }
434
+ const dot = new sphere.Dot(position, options);
435
+ dotRef.current = dot;
436
+ map.Overlays.add(dot);
437
+ const handleOverlayClick = (data) => {
438
+ if (data.overlay === dot) {
439
+ callbacksRef.current.onClick?.(dot);
440
+ }
441
+ };
442
+ const handleOverlayDrag = (overlay) => {
443
+ if (overlay === dot) {
444
+ callbacksRef.current.onDrag?.(dot);
445
+ }
446
+ };
447
+ const handleOverlayDrop = (overlay) => {
448
+ if (overlay === dot) {
449
+ const newLocation = dot.location();
450
+ callbacksRef.current.onDrop?.(dot, newLocation);
451
+ }
452
+ };
453
+ map.Event.bind("overlayClick", handleOverlayClick);
454
+ map.Event.bind("overlayDrag", handleOverlayDrag);
455
+ map.Event.bind("overlayDrop", handleOverlayDrop);
456
+ return () => {
457
+ map.Event.unbind("overlayClick", handleOverlayClick);
458
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
459
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
460
+ map.Overlays.remove(dot);
461
+ dotRef.current = null;
462
+ };
463
+ }, [
464
+ isReady,
465
+ map,
466
+ sphere,
467
+ position,
468
+ title,
469
+ detail,
470
+ visibleRange,
471
+ lineWidth,
472
+ lineColor,
473
+ clickable,
474
+ draggable,
475
+ zIndex
476
+ ]);
477
+ useImperativeHandle2(
478
+ ref,
479
+ () => ({
480
+ getDot: () => dotRef.current,
481
+ setPosition: (location) => {
482
+ dotRef.current?.location(location);
483
+ },
484
+ getPosition: () => dotRef.current?.location() ?? null
485
+ }),
486
+ []
487
+ );
488
+ return null;
489
+ });
490
+
491
+ // src/components/Layer.tsx
492
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
493
+ function Layer({
494
+ name,
495
+ preset,
496
+ isBase = false,
497
+ type,
498
+ url,
499
+ zoomRange,
500
+ source,
501
+ opacity,
502
+ zIndex,
503
+ bound,
504
+ attribution,
505
+ extraQuery,
506
+ id,
507
+ format,
508
+ srs,
509
+ tileMatrixPrefix,
510
+ styles,
511
+ version,
512
+ refresh,
513
+ zoomOffset,
514
+ beforeId
515
+ }) {
516
+ const { map, isReady } = useMapContext();
517
+ const { sphere } = useSphereContext();
518
+ const layerRef = useRef4(null);
519
+ useEffect4(() => {
520
+ if (!(isReady && map && sphere)) {
521
+ return;
522
+ }
523
+ let layer = null;
524
+ if (preset && sphere.Layers[preset]) {
525
+ layer = sphere.Layers[preset];
526
+ } else if (name) {
527
+ const options = {};
528
+ if (type) {
529
+ options.type = type;
530
+ }
531
+ if (url) {
532
+ options.url = url;
533
+ }
534
+ if (zoomRange) {
535
+ options.zoomRange = zoomRange;
536
+ }
537
+ if (source) {
538
+ options.source = source;
539
+ }
540
+ if (typeof opacity === "number") {
541
+ options.opacity = opacity;
542
+ }
543
+ if (typeof zIndex === "number") {
544
+ options.zIndex = zIndex;
545
+ }
546
+ if (bound) {
547
+ options.bound = bound;
548
+ }
549
+ if (attribution) {
550
+ options.attribution = attribution;
551
+ }
552
+ if (extraQuery) {
553
+ options.extraQuery = extraQuery;
554
+ }
555
+ if (id) {
556
+ options.id = id;
557
+ }
558
+ if (format) {
559
+ options.format = format;
560
+ }
561
+ if (srs) {
562
+ options.srs = srs;
563
+ }
564
+ if (tileMatrixPrefix) {
565
+ options.tileMatrixPrefix = tileMatrixPrefix;
566
+ }
567
+ if (styles) {
568
+ options.styles = styles;
569
+ }
570
+ if (version) {
571
+ options.version = version;
572
+ }
573
+ if (typeof refresh === "number") {
574
+ options.refresh = refresh;
575
+ }
576
+ if (typeof zoomOffset === "number") {
577
+ options.zoomOffset = zoomOffset;
578
+ }
579
+ layer = new sphere.Layer(name, options);
580
+ } else {
581
+ return;
582
+ }
583
+ layerRef.current = layer;
584
+ if (isBase) {
585
+ map.Layers.setBase(layer);
586
+ } else {
587
+ map.Layers.add(layer, beforeId);
588
+ }
589
+ return () => {
590
+ if (!isBase && layerRef.current) {
591
+ map.Layers.remove(layerRef.current);
592
+ }
593
+ layerRef.current = null;
594
+ };
595
+ }, [
596
+ isReady,
597
+ map,
598
+ sphere,
599
+ name,
600
+ preset,
601
+ isBase,
602
+ type,
603
+ url,
604
+ zoomRange,
605
+ source,
606
+ opacity,
607
+ zIndex,
608
+ bound,
609
+ attribution,
610
+ extraQuery,
611
+ id,
612
+ format,
613
+ srs,
614
+ tileMatrixPrefix,
615
+ styles,
616
+ version,
617
+ refresh,
618
+ zoomOffset,
619
+ beforeId
620
+ ]);
621
+ return null;
622
+ }
623
+
624
+ // src/components/Marker.tsx
625
+ import { forwardRef as forwardRef3, useEffect as useEffect5, useImperativeHandle as useImperativeHandle3, useRef as useRef5 } from "react";
626
+ var Marker = forwardRef3(function Marker2({
627
+ position,
628
+ icon,
629
+ title,
630
+ detail,
631
+ popup,
632
+ visibleRange,
633
+ clickable,
634
+ draggable,
635
+ zIndex,
636
+ rotate,
637
+ onClick,
638
+ onDrag,
639
+ onDrop,
640
+ onHover,
641
+ onLeave
642
+ }, ref) {
643
+ const { map, isReady } = useMapContext();
644
+ const { sphere } = useSphereContext();
645
+ const markerRef = useRef5(null);
646
+ const callbacksRef = useRef5({ onClick, onDrag, onDrop, onHover, onLeave });
647
+ useEffect5(() => {
648
+ callbacksRef.current = { onClick, onDrag, onDrop, onHover, onLeave };
649
+ }, [onClick, onDrag, onDrop, onHover, onLeave]);
650
+ useEffect5(() => {
651
+ if (!(isReady && map && sphere)) {
652
+ return;
653
+ }
654
+ const options = {};
655
+ if (icon) {
656
+ options.icon = icon;
657
+ }
658
+ if (title) {
659
+ options.title = title;
660
+ }
661
+ if (detail) {
662
+ options.detail = detail;
663
+ }
664
+ if (popup) {
665
+ options.popup = popup;
666
+ }
667
+ if (visibleRange) {
668
+ options.visibleRange = visibleRange;
669
+ }
670
+ if (typeof clickable === "boolean") {
671
+ options.clickable = clickable;
672
+ }
673
+ if (typeof draggable === "boolean") {
674
+ options.draggable = draggable;
675
+ }
676
+ if (typeof zIndex === "number") {
677
+ options.zIndex = zIndex;
678
+ }
679
+ if (typeof rotate === "number") {
680
+ options.rotate = rotate;
681
+ }
682
+ const marker = new sphere.Marker(position, options);
683
+ markerRef.current = marker;
684
+ map.Overlays.add(marker);
685
+ const handleOverlayClick = (data) => {
686
+ if (data.overlay === marker) {
687
+ callbacksRef.current.onClick?.(marker);
688
+ }
689
+ };
690
+ const handleOverlayDrag = (overlay) => {
691
+ if (overlay === marker) {
692
+ callbacksRef.current.onDrag?.(marker);
693
+ }
694
+ };
695
+ const handleOverlayDrop = (overlay) => {
696
+ if (overlay === marker) {
697
+ const newLocation = marker.location();
698
+ callbacksRef.current.onDrop?.(marker, newLocation);
699
+ }
700
+ };
701
+ const handleOverlayHover = (overlay) => {
702
+ if (overlay === marker) {
703
+ callbacksRef.current.onHover?.(marker);
704
+ }
705
+ };
706
+ const handleOverlayLeave = (overlay) => {
707
+ if (overlay === marker) {
708
+ callbacksRef.current.onLeave?.(marker);
709
+ }
710
+ };
711
+ map.Event.bind("overlayClick", handleOverlayClick);
712
+ map.Event.bind("overlayDrag", handleOverlayDrag);
713
+ map.Event.bind("overlayDrop", handleOverlayDrop);
714
+ map.Event.bind("overlayHover", handleOverlayHover);
715
+ map.Event.bind("overlayLeave", handleOverlayLeave);
716
+ return () => {
717
+ map.Event.unbind("overlayClick", handleOverlayClick);
718
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
719
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
720
+ map.Event.unbind("overlayHover", handleOverlayHover);
721
+ map.Event.unbind("overlayLeave", handleOverlayLeave);
722
+ map.Overlays.remove(marker);
723
+ markerRef.current = null;
724
+ };
725
+ }, [
726
+ isReady,
727
+ map,
728
+ sphere,
729
+ position,
730
+ icon,
731
+ title,
732
+ detail,
733
+ popup,
734
+ visibleRange,
735
+ clickable,
736
+ draggable,
737
+ zIndex,
738
+ rotate
739
+ ]);
740
+ useEffect5(() => {
741
+ if (markerRef.current && position) {
742
+ markerRef.current.location(position, false);
743
+ }
744
+ }, [position]);
745
+ useEffect5(() => {
746
+ if (markerRef.current && typeof rotate === "number") {
747
+ markerRef.current.update({ rotate });
748
+ }
749
+ }, [rotate]);
750
+ useImperativeHandle3(
751
+ ref,
752
+ () => ({
753
+ getMarker: () => markerRef.current,
754
+ togglePopup: (show) => {
755
+ markerRef.current?.pop(show);
756
+ },
757
+ setPosition: (location, animate = false) => {
758
+ markerRef.current?.location(location, animate);
759
+ },
760
+ setRotation: (angle) => {
761
+ markerRef.current?.update({ rotate: angle });
762
+ }
763
+ }),
764
+ []
765
+ );
766
+ return null;
767
+ });
768
+
769
+ // src/components/Polygon.tsx
770
+ import { forwardRef as forwardRef4, useEffect as useEffect6, useImperativeHandle as useImperativeHandle4, useRef as useRef6 } from "react";
771
+ var Polygon = forwardRef4(function Polygon2({
772
+ positions,
773
+ title,
774
+ detail,
775
+ label,
776
+ labelOptions,
777
+ popup,
778
+ visibleRange,
779
+ lineWidth,
780
+ lineColor,
781
+ fillColor,
782
+ lineStyle,
783
+ pivot,
784
+ clickable,
785
+ draggable,
786
+ pointer,
787
+ zIndex,
788
+ editable,
789
+ onClick,
790
+ onDrag,
791
+ onDrop
792
+ }, ref) {
793
+ const { map, isReady } = useMapContext();
794
+ const { sphere } = useSphereContext();
795
+ const polygonRef = useRef6(null);
796
+ const callbacksRef = useRef6({ onClick, onDrag, onDrop });
797
+ useEffect6(() => {
798
+ callbacksRef.current = { onClick, onDrag, onDrop };
799
+ }, [onClick, onDrag, onDrop]);
800
+ useEffect6(() => {
801
+ if (!(isReady && map && sphere) || positions.length < 3) {
802
+ return;
803
+ }
804
+ const options = {};
805
+ if (title) {
806
+ options.title = title;
807
+ }
808
+ if (detail) {
809
+ options.detail = detail;
810
+ }
811
+ if (label) {
812
+ options.label = label;
813
+ }
814
+ if (labelOptions) {
815
+ options.labelOptions = labelOptions;
816
+ }
817
+ if (popup) {
818
+ options.popup = popup;
819
+ }
820
+ if (visibleRange) {
821
+ options.visibleRange = visibleRange;
822
+ }
823
+ if (typeof lineWidth === "number") {
824
+ options.lineWidth = lineWidth;
825
+ }
826
+ if (lineColor) {
827
+ options.lineColor = lineColor;
828
+ }
829
+ if (fillColor) {
830
+ options.fillColor = fillColor;
831
+ }
832
+ if (lineStyle) {
833
+ options.lineStyle = lineStyle;
834
+ }
835
+ if (pivot) {
836
+ options.pivot = pivot;
837
+ }
838
+ if (typeof clickable === "boolean") {
839
+ options.clickable = clickable;
840
+ }
841
+ if (typeof draggable === "boolean") {
842
+ options.draggable = draggable;
843
+ }
844
+ if (typeof pointer === "boolean") {
845
+ options.pointer = pointer;
846
+ }
847
+ if (typeof zIndex === "number") {
848
+ options.zIndex = zIndex;
849
+ }
850
+ if (typeof editable === "boolean") {
851
+ options.editable = editable;
852
+ }
853
+ const polygon = new sphere.Polygon(positions, options);
854
+ polygonRef.current = polygon;
855
+ map.Overlays.add(polygon);
856
+ const handleOverlayClick = (data) => {
857
+ if (data.overlay === polygon) {
858
+ callbacksRef.current.onClick?.(polygon);
859
+ }
860
+ };
861
+ const handleOverlayDrag = (overlay) => {
862
+ if (overlay === polygon) {
863
+ callbacksRef.current.onDrag?.(polygon);
864
+ }
865
+ };
866
+ const handleOverlayDrop = (overlay) => {
867
+ if (overlay === polygon) {
868
+ callbacksRef.current.onDrop?.(polygon);
869
+ }
870
+ };
871
+ map.Event.bind("overlayClick", handleOverlayClick);
872
+ map.Event.bind("overlayDrag", handleOverlayDrag);
873
+ map.Event.bind("overlayDrop", handleOverlayDrop);
874
+ return () => {
875
+ map.Event.unbind("overlayClick", handleOverlayClick);
876
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
877
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
878
+ map.Overlays.remove(polygon);
879
+ polygonRef.current = null;
880
+ };
881
+ }, [
882
+ isReady,
883
+ map,
884
+ sphere,
885
+ positions,
886
+ title,
887
+ detail,
888
+ label,
889
+ labelOptions,
890
+ popup,
891
+ visibleRange,
892
+ lineWidth,
893
+ lineColor,
894
+ fillColor,
895
+ lineStyle,
896
+ pivot,
897
+ clickable,
898
+ draggable,
899
+ pointer,
900
+ zIndex,
901
+ editable
902
+ ]);
903
+ useImperativeHandle4(
904
+ ref,
905
+ () => ({
906
+ getPolygon: () => polygonRef.current,
907
+ togglePopup: (show, location) => {
908
+ polygonRef.current?.pop(show, location);
909
+ },
910
+ getPivot: () => polygonRef.current?.pivot() ?? null,
911
+ getCentroid: () => polygonRef.current?.centroid() ?? null,
912
+ getBound: () => polygonRef.current?.bound() ?? null,
913
+ getArea: (language) => polygonRef.current?.size(language) ?? null,
914
+ rotate: (angle) => {
915
+ polygonRef.current?.rotate(angle);
916
+ },
917
+ updateStyle: (options) => {
918
+ polygonRef.current?.update(options);
919
+ },
920
+ toGeoJSON: () => polygonRef.current?.toJSON() ?? null
921
+ }),
922
+ []
923
+ );
924
+ return null;
925
+ });
926
+
927
+ // src/components/Polyline.tsx
928
+ import { forwardRef as forwardRef5, useEffect as useEffect7, useImperativeHandle as useImperativeHandle5, useRef as useRef7 } from "react";
929
+ var Polyline = forwardRef5(
930
+ function Polyline2({
931
+ positions,
932
+ title,
933
+ detail,
934
+ label,
935
+ labelOptions,
936
+ popup,
937
+ visibleRange,
938
+ lineWidth,
939
+ lineColor,
940
+ lineStyle,
941
+ pivot,
942
+ clickable,
943
+ draggable,
944
+ pointer,
945
+ zIndex,
946
+ onClick,
947
+ onDrag,
948
+ onDrop
949
+ }, ref) {
950
+ const { map, isReady } = useMapContext();
951
+ const { sphere } = useSphereContext();
952
+ const polylineRef = useRef7(null);
953
+ const callbacksRef = useRef7({ onClick, onDrag, onDrop });
954
+ useEffect7(() => {
955
+ callbacksRef.current = { onClick, onDrag, onDrop };
956
+ }, [onClick, onDrag, onDrop]);
957
+ useEffect7(() => {
958
+ if (!(isReady && map && sphere) || positions.length < 2) {
959
+ return;
960
+ }
961
+ const options = {};
962
+ if (title) {
963
+ options.title = title;
964
+ }
965
+ if (detail) {
966
+ options.detail = detail;
967
+ }
968
+ if (label) {
969
+ options.label = label;
970
+ }
971
+ if (labelOptions) {
972
+ options.labelOptions = labelOptions;
973
+ }
974
+ if (popup) {
975
+ options.popup = popup;
976
+ }
977
+ if (visibleRange) {
978
+ options.visibleRange = visibleRange;
979
+ }
980
+ if (typeof lineWidth === "number") {
981
+ options.lineWidth = lineWidth;
982
+ }
983
+ if (lineColor) {
984
+ options.lineColor = lineColor;
985
+ }
986
+ if (lineStyle) {
987
+ options.lineStyle = lineStyle;
988
+ }
989
+ if (pivot) {
990
+ options.pivot = pivot;
991
+ }
992
+ if (typeof clickable === "boolean") {
993
+ options.clickable = clickable;
994
+ }
995
+ if (typeof draggable === "boolean") {
996
+ options.draggable = draggable;
997
+ }
998
+ if (typeof pointer === "boolean") {
999
+ options.pointer = pointer;
1000
+ }
1001
+ if (typeof zIndex === "number") {
1002
+ options.zIndex = zIndex;
1003
+ }
1004
+ const polyline = new sphere.Polyline(positions, options);
1005
+ polylineRef.current = polyline;
1006
+ map.Overlays.add(polyline);
1007
+ const handleOverlayClick = (data) => {
1008
+ if (data.overlay === polyline) {
1009
+ callbacksRef.current.onClick?.(polyline);
1010
+ }
1011
+ };
1012
+ const handleOverlayDrag = (overlay) => {
1013
+ if (overlay === polyline) {
1014
+ callbacksRef.current.onDrag?.(polyline);
1015
+ }
1016
+ };
1017
+ const handleOverlayDrop = (overlay) => {
1018
+ if (overlay === polyline) {
1019
+ callbacksRef.current.onDrop?.(polyline);
1020
+ }
1021
+ };
1022
+ map.Event.bind("overlayClick", handleOverlayClick);
1023
+ map.Event.bind("overlayDrag", handleOverlayDrag);
1024
+ map.Event.bind("overlayDrop", handleOverlayDrop);
1025
+ return () => {
1026
+ map.Event.unbind("overlayClick", handleOverlayClick);
1027
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
1028
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
1029
+ map.Overlays.remove(polyline);
1030
+ polylineRef.current = null;
1031
+ };
1032
+ }, [
1033
+ isReady,
1034
+ map,
1035
+ sphere,
1036
+ positions,
1037
+ title,
1038
+ detail,
1039
+ label,
1040
+ labelOptions,
1041
+ popup,
1042
+ visibleRange,
1043
+ lineWidth,
1044
+ lineColor,
1045
+ lineStyle,
1046
+ pivot,
1047
+ clickable,
1048
+ draggable,
1049
+ pointer,
1050
+ zIndex
1051
+ ]);
1052
+ useImperativeHandle5(
1053
+ ref,
1054
+ () => ({
1055
+ getPolyline: () => polylineRef.current,
1056
+ togglePopup: (show, location) => {
1057
+ polylineRef.current?.pop(show, location);
1058
+ },
1059
+ getPivot: () => polylineRef.current?.pivot() ?? null,
1060
+ getCentroid: () => polylineRef.current?.centroid() ?? null,
1061
+ getBound: () => polylineRef.current?.bound() ?? null,
1062
+ getLength: (language) => polylineRef.current?.size(language) ?? null,
1063
+ rotate: (angle) => {
1064
+ polylineRef.current?.rotate(angle);
1065
+ },
1066
+ updateStyle: (options) => {
1067
+ polylineRef.current?.update(options);
1068
+ }
1069
+ }),
1070
+ []
1071
+ );
1072
+ return null;
1073
+ }
1074
+ );
1075
+
1076
+ // src/components/Popup.tsx
1077
+ import { forwardRef as forwardRef6, useEffect as useEffect8, useImperativeHandle as useImperativeHandle6, useRef as useRef8 } from "react";
1078
+ var Popup = forwardRef6(function Popup2({
1079
+ position,
1080
+ title,
1081
+ detail,
1082
+ loadDetail,
1083
+ html,
1084
+ loadHtml,
1085
+ size,
1086
+ closable = true,
1087
+ onClose
1088
+ }, ref) {
1089
+ const { map, isReady } = useMapContext();
1090
+ const { sphere } = useSphereContext();
1091
+ const popupRef = useRef8(null);
1092
+ const onCloseRef = useRef8(onClose);
1093
+ useEffect8(() => {
1094
+ onCloseRef.current = onClose;
1095
+ }, [onClose]);
1096
+ useEffect8(() => {
1097
+ if (!(isReady && map && sphere)) {
1098
+ return;
1099
+ }
1100
+ const options = {
1101
+ closable
1102
+ };
1103
+ if (title) {
1104
+ options.title = title;
1105
+ }
1106
+ if (detail) {
1107
+ options.detail = detail;
1108
+ }
1109
+ if (loadDetail) {
1110
+ options.loadDetail = loadDetail;
1111
+ }
1112
+ if (html) {
1113
+ options.html = html;
1114
+ }
1115
+ if (loadHtml) {
1116
+ options.loadHtml = loadHtml;
1117
+ }
1118
+ if (size) {
1119
+ options.size = size;
1120
+ }
1121
+ const popup = new sphere.Popup(position, options);
1122
+ popupRef.current = popup;
1123
+ map.Overlays.add(popup);
1124
+ const handlePopupClose = (closedPopup) => {
1125
+ if (closedPopup === popup) {
1126
+ onCloseRef.current?.(popup);
1127
+ }
1128
+ };
1129
+ map.Event.bind("popupClose", handlePopupClose);
1130
+ return () => {
1131
+ map.Event.unbind("popupClose", handlePopupClose);
1132
+ map.Overlays.remove(popup);
1133
+ popupRef.current = null;
1134
+ };
1135
+ }, [
1136
+ isReady,
1137
+ map,
1138
+ sphere,
1139
+ position,
1140
+ title,
1141
+ detail,
1142
+ loadDetail,
1143
+ html,
1144
+ loadHtml,
1145
+ size,
1146
+ closable
1147
+ ]);
1148
+ useImperativeHandle6(
1149
+ ref,
1150
+ () => ({
1151
+ getPopup: () => popupRef.current,
1152
+ setPosition: (location) => {
1153
+ popupRef.current?.location(location);
1154
+ },
1155
+ setTitle: (newTitle) => {
1156
+ popupRef.current?.title(newTitle);
1157
+ },
1158
+ setDetail: (newDetail) => {
1159
+ popupRef.current?.detail(newDetail);
1160
+ },
1161
+ getElement: () => popupRef.current?.element() ?? null
1162
+ }),
1163
+ []
1164
+ );
1165
+ return null;
1166
+ });
1167
+
1168
+ // src/components/Rectangle.tsx
1169
+ import { forwardRef as forwardRef7, useEffect as useEffect9, useImperativeHandle as useImperativeHandle7, useRef as useRef9 } from "react";
1170
+ var Rectangle = forwardRef7(
1171
+ function Rectangle2({
1172
+ position,
1173
+ size,
1174
+ title,
1175
+ detail,
1176
+ popup,
1177
+ visibleRange,
1178
+ lineWidth,
1179
+ lineColor,
1180
+ fillColor,
1181
+ lineStyle,
1182
+ clickable,
1183
+ draggable,
1184
+ editable,
1185
+ zIndex,
1186
+ onClick,
1187
+ onDrag,
1188
+ onDrop
1189
+ }, ref) {
1190
+ const { map, isReady } = useMapContext();
1191
+ const { sphere } = useSphereContext();
1192
+ const rectangleRef = useRef9(null);
1193
+ const callbacksRef = useRef9({ onClick, onDrag, onDrop });
1194
+ useEffect9(() => {
1195
+ callbacksRef.current = { onClick, onDrag, onDrop };
1196
+ }, [onClick, onDrag, onDrop]);
1197
+ useEffect9(() => {
1198
+ if (!(isReady && map && sphere)) {
1199
+ return;
1200
+ }
1201
+ const options = {};
1202
+ if (title) {
1203
+ options.title = title;
1204
+ }
1205
+ if (detail) {
1206
+ options.detail = detail;
1207
+ }
1208
+ if (popup) {
1209
+ options.popup = popup;
1210
+ }
1211
+ if (visibleRange) {
1212
+ options.visibleRange = visibleRange;
1213
+ }
1214
+ if (typeof lineWidth === "number") {
1215
+ options.lineWidth = lineWidth;
1216
+ }
1217
+ if (lineColor) {
1218
+ options.lineColor = lineColor;
1219
+ }
1220
+ if (fillColor) {
1221
+ options.fillColor = fillColor;
1222
+ }
1223
+ if (lineStyle) {
1224
+ options.lineStyle = lineStyle;
1225
+ }
1226
+ if (typeof clickable === "boolean") {
1227
+ options.clickable = clickable;
1228
+ }
1229
+ if (typeof draggable === "boolean") {
1230
+ options.draggable = draggable;
1231
+ }
1232
+ if (typeof editable === "boolean") {
1233
+ options.editable = editable;
1234
+ }
1235
+ if (typeof zIndex === "number") {
1236
+ options.zIndex = zIndex;
1237
+ }
1238
+ const rectangle = new sphere.Rectangle(position, size, options);
1239
+ rectangleRef.current = rectangle;
1240
+ map.Overlays.add(rectangle);
1241
+ const handleOverlayClick = (data) => {
1242
+ if (data.overlay === rectangle) {
1243
+ callbacksRef.current.onClick?.(rectangle);
1244
+ }
1245
+ };
1246
+ const handleOverlayDrag = (overlay) => {
1247
+ if (overlay === rectangle) {
1248
+ callbacksRef.current.onDrag?.(rectangle);
1249
+ }
1250
+ };
1251
+ const handleOverlayDrop = (overlay) => {
1252
+ if (overlay === rectangle) {
1253
+ callbacksRef.current.onDrop?.(rectangle);
1254
+ }
1255
+ };
1256
+ map.Event.bind("overlayClick", handleOverlayClick);
1257
+ map.Event.bind("overlayDrag", handleOverlayDrag);
1258
+ map.Event.bind("overlayDrop", handleOverlayDrop);
1259
+ return () => {
1260
+ map.Event.unbind("overlayClick", handleOverlayClick);
1261
+ map.Event.unbind("overlayDrag", handleOverlayDrag);
1262
+ map.Event.unbind("overlayDrop", handleOverlayDrop);
1263
+ map.Overlays.remove(rectangle);
1264
+ rectangleRef.current = null;
1265
+ };
1266
+ }, [
1267
+ isReady,
1268
+ map,
1269
+ sphere,
1270
+ position,
1271
+ size,
1272
+ title,
1273
+ detail,
1274
+ popup,
1275
+ visibleRange,
1276
+ lineWidth,
1277
+ lineColor,
1278
+ fillColor,
1279
+ lineStyle,
1280
+ clickable,
1281
+ draggable,
1282
+ editable,
1283
+ zIndex
1284
+ ]);
1285
+ useImperativeHandle7(
1286
+ ref,
1287
+ () => ({
1288
+ getRectangle: () => rectangleRef.current,
1289
+ togglePopup: (show, location) => {
1290
+ rectangleRef.current?.pop(show, location);
1291
+ },
1292
+ getBound: () => rectangleRef.current?.bound() ?? null,
1293
+ getArea: (language) => rectangleRef.current?.size(language) ?? null,
1294
+ updateStyle: (options) => {
1295
+ rectangleRef.current?.update(options);
1296
+ }
1297
+ }),
1298
+ []
1299
+ );
1300
+ return null;
1301
+ }
1302
+ );
1303
+
1304
+ // src/components/SphereMap.tsx
1305
+ import {
1306
+ forwardRef as forwardRef8,
1307
+ useEffect as useEffect10,
1308
+ useImperativeHandle as useImperativeHandle8,
1309
+ useRef as useRef10,
1310
+ useState as useState2
1311
+ } from "react";
1312
+ import { jsx as jsx3 } from "react/jsx-runtime";
1313
+ var SphereMap = forwardRef8(
1314
+ function SphereMap2({
1315
+ children,
1316
+ zoom = 7,
1317
+ zoomRange,
1318
+ center,
1319
+ language = "th",
1320
+ input = true,
1321
+ lastView = false,
1322
+ ui,
1323
+ filter,
1324
+ rotate,
1325
+ pitch,
1326
+ className,
1327
+ style,
1328
+ id,
1329
+ onReady,
1330
+ onZoom,
1331
+ onLocation,
1332
+ onClick,
1333
+ onDoubleClick,
1334
+ onRotate,
1335
+ onPitch,
1336
+ onDrag,
1337
+ onDrop,
1338
+ onIdle,
1339
+ onMouseMove,
1340
+ onError
1341
+ }, ref) {
1342
+ const containerRef = useRef10(null);
1343
+ const mapRef = useRef10(null);
1344
+ const [isReady, setIsReady] = useState2(false);
1345
+ const { sphere, isLoaded, registerMap, unregisterMap } = useSphereContext();
1346
+ const callbacksRef = useRef10({
1347
+ onReady,
1348
+ onZoom,
1349
+ onLocation,
1350
+ onClick,
1351
+ onDoubleClick,
1352
+ onRotate,
1353
+ onPitch,
1354
+ onDrag,
1355
+ onDrop,
1356
+ onIdle,
1357
+ onMouseMove,
1358
+ onError
1359
+ });
1360
+ useEffect10(() => {
1361
+ callbacksRef.current = {
1362
+ onReady,
1363
+ onZoom,
1364
+ onLocation,
1365
+ onClick,
1366
+ onDoubleClick,
1367
+ onRotate,
1368
+ onPitch,
1369
+ onDrag,
1370
+ onDrop,
1371
+ onIdle,
1372
+ onMouseMove,
1373
+ onError
1374
+ };
1375
+ });
1376
+ const initialPropsRef = useRef10({
1377
+ zoom,
1378
+ zoomRange,
1379
+ center,
1380
+ language,
1381
+ input,
1382
+ lastView,
1383
+ ui,
1384
+ filter,
1385
+ rotate,
1386
+ pitch
1387
+ });
1388
+ useEffect10(() => {
1389
+ if (!(isLoaded && sphere && containerRef.current)) {
1390
+ return;
1391
+ }
1392
+ const initialProps = initialPropsRef.current;
1393
+ try {
1394
+ const options = {
1395
+ placeholder: containerRef.current,
1396
+ zoom: initialProps.zoom,
1397
+ language: initialProps.language,
1398
+ input: initialProps.input,
1399
+ lastView: initialProps.lastView
1400
+ };
1401
+ if (initialProps.zoomRange) {
1402
+ options.zoomRange = initialProps.zoomRange;
1403
+ }
1404
+ if (initialProps.center) {
1405
+ options.location = initialProps.center;
1406
+ }
1407
+ if (initialProps.ui) {
1408
+ options.ui = initialProps.ui;
1409
+ }
1410
+ const map = new sphere.Map(options);
1411
+ mapRef.current = map;
1412
+ map.Event.bind("ready", () => {
1413
+ setIsReady(true);
1414
+ registerMap(map);
1415
+ if (initialProps.filter && window.sphere) {
1416
+ map.enableFilter(window.sphere.Filter[initialProps.filter]);
1417
+ }
1418
+ if (typeof initialProps.rotate === "number") {
1419
+ map.rotate(initialProps.rotate, false);
1420
+ }
1421
+ if (typeof initialProps.pitch === "number") {
1422
+ map.pitch(initialProps.pitch);
1423
+ }
1424
+ callbacksRef.current.onReady?.(map);
1425
+ });
1426
+ map.Event.bind("zoom", () => {
1427
+ const currentZoom = map.zoom();
1428
+ callbacksRef.current.onZoom?.(currentZoom);
1429
+ });
1430
+ map.Event.bind("location", () => {
1431
+ const currentLocation = map.location();
1432
+ callbacksRef.current.onLocation?.(currentLocation);
1433
+ });
1434
+ map.Event.bind("click", (location) => {
1435
+ callbacksRef.current.onClick?.(location);
1436
+ });
1437
+ map.Event.bind("doubleClick", (location) => {
1438
+ callbacksRef.current.onDoubleClick?.(location);
1439
+ });
1440
+ map.Event.bind("rotate", () => {
1441
+ const angle = map.rotate();
1442
+ callbacksRef.current.onRotate?.(angle);
1443
+ });
1444
+ map.Event.bind("pitch", () => {
1445
+ const angle = map.pitch();
1446
+ callbacksRef.current.onPitch?.(angle);
1447
+ });
1448
+ map.Event.bind("drag", () => {
1449
+ callbacksRef.current.onDrag?.();
1450
+ });
1451
+ map.Event.bind("drop", () => {
1452
+ callbacksRef.current.onDrop?.();
1453
+ });
1454
+ map.Event.bind("idle", () => {
1455
+ callbacksRef.current.onIdle?.();
1456
+ });
1457
+ map.Event.bind("mousemove", (location) => {
1458
+ callbacksRef.current.onMouseMove?.(location);
1459
+ });
1460
+ map.Event.bind("error", (error) => {
1461
+ callbacksRef.current.onError?.(error);
1462
+ });
1463
+ } catch (error) {
1464
+ callbacksRef.current.onError?.(
1465
+ error instanceof Error ? error : new Error(String(error))
1466
+ );
1467
+ }
1468
+ return () => {
1469
+ unregisterMap();
1470
+ mapRef.current = null;
1471
+ setIsReady(false);
1472
+ };
1473
+ }, [isLoaded, sphere, registerMap, unregisterMap]);
1474
+ useImperativeHandle8(
1475
+ ref,
1476
+ () => ({
1477
+ getMap: () => mapRef.current,
1478
+ setZoom: (newZoom, animate = true) => {
1479
+ mapRef.current?.zoom(newZoom, animate);
1480
+ },
1481
+ setCenter: (location, animate = true) => {
1482
+ mapRef.current?.location(location, animate);
1483
+ },
1484
+ setBound: (bound, options) => {
1485
+ mapRef.current?.bound(bound, options);
1486
+ },
1487
+ goTo: (target, animate = true) => {
1488
+ mapRef.current?.goTo(target, animate);
1489
+ },
1490
+ setRotate: (angle, animate = true) => {
1491
+ mapRef.current?.rotate(angle, animate);
1492
+ },
1493
+ setPitch: (angle) => {
1494
+ mapRef.current?.pitch(angle);
1495
+ },
1496
+ setFilter: (newFilter) => {
1497
+ if (mapRef.current && window.sphere) {
1498
+ mapRef.current.enableFilter(window.sphere.Filter[newFilter]);
1499
+ }
1500
+ },
1501
+ resize: () => {
1502
+ mapRef.current?.resize();
1503
+ },
1504
+ repaint: () => {
1505
+ mapRef.current?.repaint();
1506
+ }
1507
+ }),
1508
+ []
1509
+ );
1510
+ const containerStyle = {
1511
+ width: "100%",
1512
+ height: "100%",
1513
+ ...style
1514
+ };
1515
+ return /* @__PURE__ */ jsx3(
1516
+ "div",
1517
+ {
1518
+ className,
1519
+ id,
1520
+ ref: containerRef,
1521
+ style: containerStyle,
1522
+ children: /* @__PURE__ */ jsx3(MapProvider, { isReady, map: mapRef.current, children: isReady && children })
1523
+ }
1524
+ );
1525
+ }
1526
+ );
1527
+ var SphereMap_default = SphereMap;
1528
+
1529
+ // src/hooks/useMapEvent.ts
1530
+ import { useEffect as useEffect11, useRef as useRef11 } from "react";
1531
+ function useMapEvent(eventName, handler) {
1532
+ const { map, isReady } = useMapContext();
1533
+ const { sphere } = useSphereContext();
1534
+ const handlerRef = useRef11(handler);
1535
+ useEffect11(() => {
1536
+ handlerRef.current = handler;
1537
+ }, [handler]);
1538
+ useEffect11(() => {
1539
+ if (!(isReady && map && sphere)) {
1540
+ return;
1541
+ }
1542
+ const stableHandler = (data) => {
1543
+ return handlerRef.current(data);
1544
+ };
1545
+ map.Event.bind(eventName, stableHandler);
1546
+ return () => {
1547
+ map.Event.unbind(eventName, stableHandler);
1548
+ };
1549
+ }, [map, isReady, sphere, eventName]);
1550
+ }
1551
+ function useMapReady(handler) {
1552
+ useMapEvent("ready", handler);
1553
+ }
1554
+ function useMapClick(handler) {
1555
+ useMapEvent("click", handler);
1556
+ }
1557
+ function useMapZoom(handler) {
1558
+ useMapEvent("zoom", handler);
1559
+ }
1560
+ function useMapLocation(handler) {
1561
+ useMapEvent("location", handler);
1562
+ }
1563
+ function useOverlayClick(handler) {
1564
+ useMapEvent("overlayClick", handler);
1565
+ }
1566
+
1567
+ // src/hooks/useOverlays.ts
1568
+ import { useCallback as useCallback2, useMemo as useMemo3, useState as useState3 } from "react";
1569
+ function generateId() {
1570
+ return `overlay-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1571
+ }
1572
+ function useOverlayState() {
1573
+ const [items, setItems] = useState3([]);
1574
+ const add = useCallback2((data) => {
1575
+ const id = data.id ?? generateId();
1576
+ const newItem = { ...data, id };
1577
+ setItems((prev) => [...prev, newItem]);
1578
+ return id;
1579
+ }, []);
1580
+ const update = useCallback2(
1581
+ (id, data) => {
1582
+ setItems(
1583
+ (prev) => prev.map((item) => item.id === id ? { ...item, ...data } : item)
1584
+ );
1585
+ },
1586
+ []
1587
+ );
1588
+ const remove = useCallback2((id) => {
1589
+ setItems((prev) => prev.filter((item) => item.id !== id));
1590
+ }, []);
1591
+ const clear = useCallback2(() => {
1592
+ setItems([]);
1593
+ }, []);
1594
+ const get = useCallback2(
1595
+ (id) => {
1596
+ return items.find((item) => item.id === id);
1597
+ },
1598
+ [items]
1599
+ );
1600
+ return useMemo3(
1601
+ () => ({ items, add, update, remove, clear, get }),
1602
+ [items, add, update, remove, clear, get]
1603
+ );
1604
+ }
1605
+ function useMarkers() {
1606
+ return useOverlayState();
1607
+ }
1608
+ function usePolygons() {
1609
+ return useOverlayState();
1610
+ }
1611
+ function usePolylines() {
1612
+ return useOverlayState();
1613
+ }
1614
+ function useCircles() {
1615
+ return useOverlayState();
1616
+ }
1617
+ function useOverlays() {
1618
+ const markers = useMarkers();
1619
+ const polygons = usePolygons();
1620
+ const polylines = usePolylines();
1621
+ const circles = useCircles();
1622
+ const clearAll = useCallback2(() => {
1623
+ markers.clear();
1624
+ polygons.clear();
1625
+ polylines.clear();
1626
+ circles.clear();
1627
+ }, [markers, polygons, polylines, circles]);
1628
+ return useMemo3(
1629
+ () => ({ markers, polygons, polylines, circles, clearAll }),
1630
+ [markers, polygons, polylines, circles, clearAll]
1631
+ );
1632
+ }
1633
+
1634
+ // src/hooks/useRoute.ts
1635
+ import { useCallback as useCallback3, useMemo as useMemo4 } from "react";
1636
+ function useRoute() {
1637
+ const { map, isReady } = useMap();
1638
+ const addDestination = useCallback3(
1639
+ (destination, mode) => {
1640
+ map?.Route?.add(destination, mode);
1641
+ },
1642
+ [map]
1643
+ );
1644
+ const insertDestination = useCallback3(
1645
+ (index, destination, mode) => {
1646
+ map?.Route?.insert(index, destination, mode);
1647
+ },
1648
+ [map]
1649
+ );
1650
+ const removeDestination = useCallback3(
1651
+ (destination) => {
1652
+ map?.Route?.remove(destination);
1653
+ },
1654
+ [map]
1655
+ );
1656
+ const removeDestinationAt = useCallback3(
1657
+ (index) => {
1658
+ map?.Route?.removeAt(index);
1659
+ },
1660
+ [map]
1661
+ );
1662
+ const clearDestinations = useCallback3(() => {
1663
+ map?.Route?.clearDestination();
1664
+ }, [map]);
1665
+ const clearPath = useCallback3(() => {
1666
+ map?.Route?.clearPath();
1667
+ }, [map]);
1668
+ const clear = useCallback3(() => {
1669
+ map?.Route?.clear();
1670
+ }, [map]);
1671
+ const reverse = useCallback3(() => {
1672
+ map?.Route?.reverse();
1673
+ }, [map]);
1674
+ const search = useCallback3(() => {
1675
+ map?.Route?.search();
1676
+ }, [map]);
1677
+ const getDistance = useCallback3(
1678
+ (format = false) => {
1679
+ return map?.Route?.distance(format) ?? 0;
1680
+ },
1681
+ [map]
1682
+ );
1683
+ const getInterval = useCallback3(
1684
+ (format = false) => {
1685
+ return map?.Route?.interval(format) ?? 0;
1686
+ },
1687
+ [map]
1688
+ );
1689
+ const getGuide = useCallback3(
1690
+ (format = false) => {
1691
+ const result = map?.Route?.guide(format);
1692
+ return result ?? [];
1693
+ },
1694
+ [map]
1695
+ );
1696
+ const exportRouteLine = useCallback3(
1697
+ (options) => {
1698
+ return map?.Route?.exportRouteLine(options) ?? null;
1699
+ },
1700
+ [map]
1701
+ );
1702
+ const listDestinations = useCallback3(() => {
1703
+ return map?.Route?.list() ?? [];
1704
+ }, [map]);
1705
+ const size = useCallback3(() => {
1706
+ return map?.Route?.size() ?? 0;
1707
+ }, [map]);
1708
+ const setMode = useCallback3(
1709
+ (mode) => {
1710
+ map?.Route?.mode(mode);
1711
+ },
1712
+ [map]
1713
+ );
1714
+ const setModeAt = useCallback3(
1715
+ (index, mode) => {
1716
+ map?.Route?.modeOf(index, mode);
1717
+ },
1718
+ [map]
1719
+ );
1720
+ const enableRouteType = useCallback3(
1721
+ (routeType, state) => {
1722
+ map?.Route?.enableRoute(routeType, state);
1723
+ },
1724
+ [map]
1725
+ );
1726
+ const setLabel = useCallback3(
1727
+ (label) => {
1728
+ map?.Route?.label(label);
1729
+ },
1730
+ [map]
1731
+ );
1732
+ const setAuto = useCallback3(
1733
+ (state) => {
1734
+ map?.Route?.auto(state);
1735
+ },
1736
+ [map]
1737
+ );
1738
+ const setLanguage = useCallback3(
1739
+ (lang) => {
1740
+ map?.Route?.language(lang);
1741
+ },
1742
+ [map]
1743
+ );
1744
+ return useMemo4(
1745
+ () => ({
1746
+ isReady,
1747
+ addDestination,
1748
+ insertDestination,
1749
+ removeDestination,
1750
+ removeDestinationAt,
1751
+ clearDestinations,
1752
+ clearPath,
1753
+ clear,
1754
+ reverse,
1755
+ search,
1756
+ getDistance,
1757
+ getInterval,
1758
+ getGuide,
1759
+ exportRouteLine,
1760
+ listDestinations,
1761
+ size,
1762
+ setMode,
1763
+ setModeAt,
1764
+ enableRouteType,
1765
+ setLabel,
1766
+ setAuto,
1767
+ setLanguage
1768
+ }),
1769
+ [
1770
+ isReady,
1771
+ addDestination,
1772
+ insertDestination,
1773
+ removeDestination,
1774
+ removeDestinationAt,
1775
+ clearDestinations,
1776
+ clearPath,
1777
+ clear,
1778
+ reverse,
1779
+ search,
1780
+ getDistance,
1781
+ getInterval,
1782
+ getGuide,
1783
+ exportRouteLine,
1784
+ listDestinations,
1785
+ size,
1786
+ setMode,
1787
+ setModeAt,
1788
+ enableRouteType,
1789
+ setLabel,
1790
+ setAuto,
1791
+ setLanguage
1792
+ ]
1793
+ );
1794
+ }
1795
+
1796
+ // src/hooks/useSearch.ts
1797
+ import { useCallback as useCallback4, useMemo as useMemo5 } from "react";
1798
+ function useSearch() {
1799
+ const { map, isReady } = useMap();
1800
+ const suggest = useCallback4(
1801
+ async (keyword, options) => {
1802
+ if (!map?.Search) {
1803
+ throw new Error("Search API not available");
1804
+ }
1805
+ return await map.Search.suggest(keyword, options);
1806
+ },
1807
+ [map]
1808
+ );
1809
+ const search = useCallback4(
1810
+ async (keyword, options) => {
1811
+ if (!map?.Search) {
1812
+ throw new Error("Search API not available");
1813
+ }
1814
+ return await map.Search.search(keyword, options);
1815
+ },
1816
+ [map]
1817
+ );
1818
+ const address = useCallback4(
1819
+ async (location, options) => {
1820
+ if (!map?.Search) {
1821
+ throw new Error("Search API not available");
1822
+ }
1823
+ return await map.Search.address(location, options);
1824
+ },
1825
+ [map]
1826
+ );
1827
+ const nearPoi = useCallback4(
1828
+ async (location, options) => {
1829
+ if (!map?.Search) {
1830
+ throw new Error("Search API not available");
1831
+ }
1832
+ const result = await map.Search.nearPoi(location, options);
1833
+ return result.data ?? result;
1834
+ },
1835
+ [map]
1836
+ );
1837
+ const clear = useCallback4(() => {
1838
+ map?.Search?.clear();
1839
+ }, [map]);
1840
+ const enablePopup = useCallback4(
1841
+ (state) => {
1842
+ map?.Search?.enablePopup(state);
1843
+ },
1844
+ [map]
1845
+ );
1846
+ const setLanguage = useCallback4(
1847
+ (lang) => {
1848
+ map?.Search?.language(lang);
1849
+ },
1850
+ [map]
1851
+ );
1852
+ return useMemo5(
1853
+ () => ({
1854
+ isReady,
1855
+ suggest,
1856
+ search,
1857
+ address,
1858
+ nearPoi,
1859
+ clear,
1860
+ enablePopup,
1861
+ setLanguage
1862
+ }),
1863
+ [
1864
+ isReady,
1865
+ suggest,
1866
+ search,
1867
+ address,
1868
+ nearPoi,
1869
+ clear,
1870
+ enablePopup,
1871
+ setLanguage
1872
+ ]
1873
+ );
1874
+ }
1875
+
1876
+ // src/hooks/useSphere.ts
1877
+ function useSphere() {
1878
+ const { sphere, isLoaded, error, apiKey } = useSphereContext();
1879
+ return {
1880
+ sphere,
1881
+ isLoaded,
1882
+ error,
1883
+ apiKey
1884
+ };
1885
+ }
1886
+
1887
+ // src/hooks/useTags.ts
1888
+ import { useCallback as useCallback5, useMemo as useMemo6 } from "react";
1889
+ var TAG_CATEGORIES = [
1890
+ {
1891
+ name: "Food & Dining",
1892
+ tags: [
1893
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E44\u0E17\u0E22", label: "Thai Food" },
1894
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E0D\u0E35\u0E48\u0E1B\u0E38\u0E48\u0E19", label: "Japanese" },
1895
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E08\u0E35\u0E19", label: "Chinese" },
1896
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E40\u0E01\u0E32\u0E2B\u0E25\u0E35", label: "Korean" },
1897
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E40\u0E27\u0E35\u0E22\u0E14\u0E19\u0E32\u0E21", label: "Vietnamese" },
1898
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E2D\u0E34\u0E19\u0E40\u0E14\u0E35\u0E22", label: "Indian" },
1899
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E2D\u0E34\u0E15\u0E32\u0E25\u0E35", label: "Italian" },
1900
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E1D\u0E23\u0E31\u0E48\u0E07\u0E40\u0E28\u0E2A", label: "French" },
1901
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E40\u0E22\u0E2D\u0E23\u0E21\u0E31\u0E19", label: "German" },
1902
+ { id: "\u0E2D\u0E32\u0E2B\u0E32\u0E23\u0E22\u0E38\u0E42\u0E23\u0E1B", label: "European" }
1903
+ ]
1904
+ },
1905
+ {
1906
+ name: "Services",
1907
+ tags: [
1908
+ { id: "\u0E18\u0E19\u0E32\u0E04\u0E32\u0E23", label: "Bank" },
1909
+ { id: "ATM", label: "ATM" },
1910
+ { id: "\u0E42\u0E23\u0E07\u0E1E\u0E22\u0E32\u0E1A\u0E32\u0E25", label: "Hospital" },
1911
+ { id: "\u0E1B\u0E31\u0E4A\u0E21\u0E19\u0E49\u0E33\u0E21\u0E31\u0E19", label: "Gas Station" }
1912
+ ]
1913
+ },
1914
+ {
1915
+ name: "Tourism",
1916
+ tags: [
1917
+ { id: "\u0E42\u0E23\u0E07\u0E41\u0E23\u0E21", label: "Hotel" },
1918
+ { id: "\u0E27\u0E31\u0E14", label: "Temple" },
1919
+ { id: "\u0E1E\u0E34\u0E1E\u0E34\u0E18\u0E20\u0E31\u0E13\u0E11\u0E4C", label: "Museum" },
1920
+ { id: "\u0E2B\u0E49\u0E32\u0E07\u0E2A\u0E23\u0E23\u0E1E\u0E2A\u0E34\u0E19\u0E04\u0E49\u0E32", label: "Shopping Mall" }
1921
+ ]
1922
+ }
1923
+ ];
1924
+ function useTags() {
1925
+ const { map, isReady } = useMap();
1926
+ const set = useCallback5(
1927
+ (tag, options) => {
1928
+ map?.Tags?.set(tag, options);
1929
+ },
1930
+ [map]
1931
+ );
1932
+ const add = useCallback5(
1933
+ (tag, options) => {
1934
+ map?.Tags?.add(tag, options);
1935
+ },
1936
+ [map]
1937
+ );
1938
+ const remove = useCallback5(
1939
+ (tag) => {
1940
+ map?.Tags?.remove(tag);
1941
+ },
1942
+ [map]
1943
+ );
1944
+ const clear = useCallback5(() => {
1945
+ map?.Tags?.clear();
1946
+ }, [map]);
1947
+ const list = useCallback5(() => {
1948
+ return map?.Tags?.list() ?? [];
1949
+ }, [map]);
1950
+ const size = useCallback5(() => {
1951
+ return map?.Tags?.size() ?? 0;
1952
+ }, [map]);
1953
+ const enablePopup = useCallback5(
1954
+ (state) => {
1955
+ map?.Tags?.enablePopup(state);
1956
+ },
1957
+ [map]
1958
+ );
1959
+ const setLanguage = useCallback5(
1960
+ (lang) => {
1961
+ map?.Tags?.language(lang);
1962
+ },
1963
+ [map]
1964
+ );
1965
+ return useMemo6(
1966
+ () => ({
1967
+ isReady,
1968
+ set,
1969
+ add,
1970
+ remove,
1971
+ clear,
1972
+ list,
1973
+ size,
1974
+ enablePopup,
1975
+ setLanguage
1976
+ }),
1977
+ [isReady, set, add, remove, clear, list, size, enablePopup, setLanguage]
1978
+ );
1979
+ }
1980
+ export {
1981
+ Circle,
1982
+ Dot,
1983
+ Layer,
1984
+ SphereMap_default as Map,
1985
+ MapProvider,
1986
+ Marker,
1987
+ Polygon,
1988
+ Polyline,
1989
+ Popup,
1990
+ Rectangle,
1991
+ SphereMap,
1992
+ SphereProvider,
1993
+ TAG_CATEGORIES,
1994
+ useCircles,
1995
+ useMap,
1996
+ useMapClick,
1997
+ useMapContext,
1998
+ useMapControls,
1999
+ useMapEvent,
2000
+ useMapLocation,
2001
+ useMapReady,
2002
+ useMapZoom,
2003
+ useMarkers,
2004
+ useOverlayClick,
2005
+ useOverlays,
2006
+ usePolygons,
2007
+ usePolylines,
2008
+ useRoute,
2009
+ useSearch,
2010
+ useSphere,
2011
+ useSphereContext,
2012
+ useTags
2013
+ };