react-bkoi-gl 2.0.1 → 2.2.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.
package/README.md CHANGED
@@ -1,250 +1,1577 @@
1
1
  <h1 align="center">react-bkoi-gl | <a href="https://docs.barikoi.com/npm/npm-intro">Docs</a></h1>
2
2
 
3
3
  <p align="center">
4
- <a href="https://www.npmjs.com/package/react-bkoi-gl"><img src="https://img.shields.io/npm/v/react-bkoi-gl.svg" alt="npm version"></a>
5
- <a href="https://www.npmjs.com/package/react-bkoi-gl"><img src="https://img.shields.io/npm/dw/react-bkoi-gl" alt="npm downloads"></a>
6
- <a href="https://bundlephobia.com/package/react-bkoi-gl"><img src="https://img.shields.io/bundlephobia/min/react-bkoi-gl" alt="Bundle Size"></a>
4
+ <a href="https://www.npmjs.com/package/react-bkoi-gl"><img src="https://img.shields.io/npm/v/react-bkoi-gl.svg?logo=npm&logoColor=white" alt="npm version"></a>
7
5
  <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white" alt="TypeScript"></a>
8
- <a href="https://nodejs.org/"><img src="https://img.shields.io/node/v/react-bkoi-gl" alt="Node.js Version"></a>
9
- <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
6
+ <a href="https://react.dev/"><img src="https://img.shields.io/badge/React-%E2%89%A518-149eca?logo=react&logoColor=white" alt="React ≥18"></a>
7
+ <a href="https://www.npmjs.com/package/react-bkoi-gl"><img src="https://img.shields.io/npm/dw/react-bkoi-gl.svg?label=downloads" alt="npm weekly downloads"></a>
8
+ <a href="https://github.com/barikoi/react-bkoi-gl/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/react-bkoi-gl.svg?label=license" alt="license"></a>
10
9
  </p>
11
10
 
12
11
  ## Description
13
12
 
14
- `react-bkoi-gl` is a suite of [React](http://facebook.github.io/react/) components designed to provide a API for [Barikoi Maps](https://docs.barikoi.com/docs/maps-api). More information in the online documentation.
13
+ `react-bkoi-gl` is a suite of [React](http://facebook.github.io/react/) components that provides a React API for [Barikoi Maps](https://docs.barikoi.com/docs/maps-api). Built on top of [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/), it offers high-performance, customizable map rendering with full TypeScript support.
14
+
15
+ Powered by <a href="https://barikoi.com/">Barikoi - Maps for Businesses</a>
16
+
17
+ ## Features
18
+
19
+ - High-performance map rendering using WebGL
20
+ - Easy integration with React and Next.js
21
+ - Customizable map controls and interactions
22
+ - Drawing tools for polygons, lines, and points
23
+ - Minimap control for navigation
24
+ - Support for GeoJSON, vector tiles, and raster sources
25
+ - Full TypeScript support
26
+ - Lightweight and optimized for production
15
27
 
16
28
  ## Installation
17
29
 
18
- Using `react-bkoi-gl` requires `react >= 16.3`.
30
+ Using `react-bkoi-gl` requires `react >= 18` (the library uses the `useId` and `useSyncExternalStore` React 18 APIs). Map rendering is bundled — no separate map engine install needed.
19
31
 
20
- To install the package via npm, run the following command:
21
32
  ```bash
22
33
  npm install react-bkoi-gl
23
34
  ```
35
+
24
36
  Or via yarn:
37
+
25
38
  ```bash
26
39
  yarn add react-bkoi-gl
27
40
  ```
28
41
 
29
- ## Example
42
+ Import styles in your application:
30
43
 
31
- ### JavaScript (`js`) Example
32
- ```jsx
33
- import { useRef } from 'react';
34
- import {
35
- Map,
36
- Marker,
37
- Popup,
38
- Layer,
39
- Source,
40
- NavigationControl,
41
- FullscreenControl,
42
- GeolocateControl,
43
- ScaleControl,
44
- } from 'react-bkoi-gl';
44
+ ```javascript
45
+ import "react-bkoi-gl/styles";
46
+ ```
47
+
48
+ ## Get Barikoi API Key
49
+
50
+ To access Barikoi's API services, you need to:
51
+
52
+ 1. Register on [Barikoi Developer Dashboard](https://developer.barikoi.com/register)
53
+ 2. Verify with your phone number
54
+ 3. Claim your API key
55
+
56
+ ### API Key Security
57
+
58
+ Your Barikoi API key is embedded in the `mapStyle` URL passed to `<Map>`, so it is exposed to the browser. Treat it accordingly:
45
59
 
46
- // Import Styles
60
+ - **Restrict keys by domain.** In the Barikoi Developer Dashboard, limit each key to the exact origins that will use it (e.g. `example.com`, `www.example.com`). A domain-restricted key is useless if it leaks.
61
+ - **Use separate keys per environment** (local dev, staging, production) so you can rotate production keys without disrupting development.
62
+ - **Load keys from configuration, not source.** Inject the key via an environment variable or your host's secret manager; never hardcode a production key in source control.
63
+ - **Rotate immediately on exposure.** If a key is committed to a public repo, appears in logs, or is shared accidentally, disable it in the dashboard and issue a replacement, then update the deployed `mapStyle` URL.
64
+ - **Monitor usage.** Review request volume in the dashboard for unexpected spikes that can indicate key theft.
65
+
66
+ > A browser-embedded key cannot be fully hidden. **Domain restriction and rotation are your primary defenses** — not obscurity.
67
+
68
+ ## Quick Start
69
+
70
+ ```tsx
71
+ import { Map, Marker, Popup, NavigationControl } from 'react-bkoi-gl';
47
72
  import "react-bkoi-gl/styles";
48
73
 
49
- const App = () => {
50
- const BARIKOI_API_KEY = 'YOUR_BARIKOI_API_KEY_HERE';
51
- const mapStyle = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`;
52
- const mapContainer = useRef(null);
53
- const mapRef = useRef(null);
54
- const initialViewState = {
55
- longitude: 90.36402,
56
- latitude: 23.823731,
57
- minZoom: 4,
58
- maxZoom: 22,
59
- zoom: 13,
60
- bearing: 0,
61
- pitch: 0,
62
- antialias: true,
63
- };
74
+ const BARIKOI_API_KEY = 'YOUR_BARIKOI_API_KEY';
64
75
 
76
+ function App() {
65
77
  return (
66
- <div ref={mapContainer} style={containerStyles}>
78
+ <div style={{ width: '100%', height: '100vh' }}>
67
79
  <Map
68
- ref={mapRef}
69
- mapStyle={mapStyle}
70
- style={{ width: "100%", height: "100%" }}
71
- initialViewState={initialViewState}
72
- doubleClickZoom={false}
73
- dragRotate={false}
80
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`}
81
+ initialViewState={{
82
+ longitude: 90.3938010872331,
83
+ latitude: 23.821600277500405,
84
+ zoom: 12
85
+ }}
74
86
  >
75
- <Marker longitude={90.36402} latitude={23.823731} color="red" />
76
- <Popup longitude={90.36402} latitude={23.823731}>
77
- <div>Hello, Barikoi!</div>
87
+ <Marker longitude={90.3938010872331} latitude={23.821600277500405} color="red" />
88
+ <Popup longitude={90.3938010872331} latitude={23.821600277500405}>
89
+ Hello, Barikoi!
78
90
  </Popup>
79
- <Source
80
- id="points"
81
- type="geojson"
82
- data={{
83
- type: 'FeatureCollection',
84
- features: [
85
- {
86
- type: 'Feature',
87
- properties: {},
88
- geometry: { type: 'Point', coordinates: [90.36402, 23.823731] }
89
- }
90
- ]
91
- }}
92
- />
93
- <Layer
94
- id="points-layer"
95
- type="circle"
96
- source="points"
97
- paint={{ 'circle-radius': 10, 'circle-color': '#ff0000' }}
98
- />
99
91
  <NavigationControl position="top-right" />
100
- <FullscreenControl position="top-right" />
101
- <GeolocateControl position="top-right" />
102
- <ScaleControl position="bottom-right" />
103
92
  </Map>
104
93
  </div>
105
94
  );
106
- };
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Requirements
107
101
 
108
- // JSX Styles
109
- const containerStyles = {
110
- width: "100%",
111
- height: "100vh",
112
- minHeight: "400px",
113
- overflow: "hidden",
114
- };
102
+ | Requirement | Version |
103
+ |-------------|---------|
104
+ | `react`, `react-dom` | `>=18.0.0` (uses `useId`, `useSyncExternalStore`) |
105
+ | Node | `>=18.18.0` (build/dev only) |
115
106
 
116
- export default App;
107
+ Map rendering is bundled — no separate map engine install needed.
108
+
109
+ ---
110
+
111
+ ## Next.js & SSR
112
+
113
+ `react-bkoi-gl` renders into a `<canvas>` and must run client-side. In Next.js App Router, mark consumer components with `"use client"`:
114
+
115
+ ```tsx
116
+ // app/MapView.tsx
117
+ "use client";
118
+
119
+ import { Map } from "react-bkoi-gl";
120
+ import "react-bkoi-gl/styles";
121
+
122
+ export default function MapView() {
123
+ return (
124
+ <Map
125
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${process.env.NEXT_PUBLIC_BARIKOI_API_KEY}`}
126
+ initialViewState={{ longitude: 90.3938, latitude: 23.8216, zoom: 12 }}
127
+ style={{ width: "100%", height: "100vh" }}
128
+ />
129
+ );
130
+ }
117
131
  ```
118
132
 
119
- ### TypeScript (`ts`) Example
133
+ The library uses `useId`, `useSyncExternalStore`, and `useLayoutEffect` — all client-only hooks. SSR will warn or crash without the directive.
134
+
135
+ For Pages Router, dynamic-import with `ssr: false`:
136
+
120
137
  ```tsx
138
+ import dynamic from "next/dynamic";
139
+ const MapView = dynamic(() => import("../components/MapView"), { ssr: false });
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Logging
145
+
146
+ All `console.warn` / `console.error` calls route through an injectable `logger`, so you can capture warnings in production or feed them to your telemetry provider.
147
+
148
+ ```tsx
149
+ import { setLogger } from "react-bkoi-gl";
150
+
151
+ setLogger({
152
+ warn: (msg, ...args) => Sentry.captureMessage(String(msg)),
153
+ error: (err, ...args) => Sentry.captureException(err),
154
+ });
155
+ ```
156
+
157
+ Non-fatal warnings (transient rendering errors before the style finishes loading, etc.) are also surfaced via the `<Map onWarning={...}>` prop when you want per-instance handling.
158
+
159
+ ---
160
+
161
+ ## Accessibility
162
+
163
+ - The map canvas gets `role="region"` and `aria-label="Map"` automatically.
164
+ - For keyboard navigation (arrow keys to pan, `+`/`-` to zoom), keep the `keyboard` prop enabled (default: `true`).
165
+ - `GlobeControl`, `MinimapControl`, `NavigationControl`, etc. set `type="button"`, `aria-label`, and `title` automatically. Custom elements passed to `GlobeControl` via `buttonElement` must be `<button>` or have `role="button"`, otherwise they are refused with a console warning.
166
+ - `MinimapControl` announces collapse/expand state via a visually-hidden `aria-live="polite"` region.
167
+
168
+ ---
169
+
170
+ ## Components
171
+
172
+ Build maps by composing the `Map` component with layers, sources, UI controls, and hooks.
173
+
174
+ ### Quick Index
175
+
176
+ #### Core
177
+
178
+ - [`Map`](#map-component): Core map component. Parent of all other components.
179
+ - [`Marker`](#marker-component): Marker at a coordinate (supports custom children).
180
+ - [`Popup`](#popup-component): Popup UI at a coordinate or attached to a marker.
181
+
182
+ #### Data & Rendering
183
+
184
+ - [`Source`](#source-component): Data source (GeoJSON, vector, raster, image, video, etc.).
185
+ - [`CanvasSource`](#canvas-source): Render a custom HTML canvas as a source.
186
+ - [`Layer`](#layer-component): Render MapLibre layers from a source (supports events).
187
+
188
+ #### Controls
189
+
190
+ - [`NavigationControl`](#navigation-control): Zoom/compass controls.
191
+ - [`FullscreenControl`](#fullscreen-control): Fullscreen toggle.
192
+ - [`GeolocateControl`](#geolocate-control): Locate and track the user.
193
+ - [`ScaleControl`](#scale-control): Scale bar.
194
+ - [`TerrainControl`](#terrain-control): Terrain visualization.
195
+ - [`DrawControl`](#draw-control): Draw/edit polygons, lines, points.
196
+ - [`GlobeControl`](#globe-control): Toggle globe projection (MapLibre 3.x+).
197
+ - [`MinimapControl`](#minimap-control): Overview minimap (toggleable, responsive).
198
+
199
+ #### Hooks
200
+
201
+ - [`useMap`](#usemap-hook): Access map instances via `MapProvider`.
202
+ - [`useControl`](#usecontrol-hook): Create custom controls.
203
+
204
+ ---
205
+
206
+ ### Map Component
207
+
208
+ The core component that renders a Barikoi map. All other components must be children of `Map`.
209
+
210
+ <details>
211
+ <summary><strong>Props</strong></summary>
212
+
213
+ | Prop | Type | Default | Description |
214
+ |------|------|---------|-------------|
215
+ | `mapStyle` | `string \| StyleSpecification` | Required | Map style URL or style object |
216
+ | `initialViewState` | `object` | - | Initial view state (longitude, latitude, zoom, etc.) |
217
+ | `viewState` | `object` | - | Controlled view state |
218
+ | `reuseMaps` | `boolean` | `false` | Reuse map instances for performance |
219
+ | `id` | `string` | - | Container element ID |
220
+ | `style` | `CSSProperties` | - | Container CSS styles |
221
+ | `children` | `ReactNode` | - | Child components |
222
+ | `onClick` | `(e: MapLayerMouseEvent) => void` | - | Click handler |
223
+ | `onLoad` | `(e: MapLibreEvent) => void` | - | Map load handler |
224
+ | `onMoveEnd` | `(e: ViewStateChangeEvent) => void` | - | Move end handler |
225
+ | `onZoomEnd` | `(e: ViewStateChangeEvent) => void` | - | Zoom end handler |
226
+ | `onError` | `(e: ErrorEvent) => void` | - | Error handler |
227
+ | `onWarning` | `(e: ErrorEvent) => void` | - | Non-fatal warning handler (e.g. transient `queryRenderedFeatures` errors before style load). Falls back to `console.warn` when omitted. |
228
+ | `showBarikoiLogo` | `boolean` | `true` | Render the Barikoi logo control (bottom-left). |
229
+ | `showAttribution` | `boolean` | `true` | Render the attribution control (bottom-right). Attribution is required by the OSM/MapLibre license terms — keep this enabled unless you provide attribution elsewhere. |
230
+
231
+ And all [MapLibre Map options](https://maplibre.org/maplibre-gl-js/docs/API/types/MapOptions/).
232
+
233
+ </details>
234
+
235
+ #### Example
236
+
237
+ ```tsx
238
+ import { Map, MapRef } from 'react-bkoi-gl';
239
+ import "react-bkoi-gl/styles";
121
240
  import { useRef } from 'react';
122
- import {
123
- Map,
124
- Marker,
125
- Popup,
126
- Layer,
127
- Source,
128
- NavigationControl,
129
- FullscreenControl,
130
- GeolocateControl,
131
- ScaleControl,
132
- MapRef
133
- } from 'react-bkoi-gl';
134
241
 
135
- // Import Styles
242
+ function MapExample() {
243
+ const mapRef = useRef<MapRef>(null);
244
+
245
+ const handleMoveEnd = (e) => {
246
+ const map = mapRef.current?.getMap();
247
+ if (map) {
248
+ console.log('Center:', map.getCenter());
249
+ console.log('Zoom:', map.getZoom());
250
+ }
251
+ };
252
+
253
+ return (
254
+ <Map
255
+ ref={mapRef}
256
+ mapStyle="https://map.barikoi.com/styles/osm-liberty/style.json?key=YOUR_API_KEY"
257
+ initialViewState={{
258
+ longitude: 90.3938,
259
+ latitude: 23.8216,
260
+ zoom: 12,
261
+ pitch: 0,
262
+ bearing: 0
263
+ }}
264
+ style={{ width: '100%', height: '100vh' }}
265
+ doubleClickZoom={false}
266
+ dragRotate={true}
267
+ onMoveEnd={handleMoveEnd}
268
+ >
269
+ {/* Child components go here */}
270
+ </Map>
271
+ );
272
+ }
273
+ ```
274
+
275
+ ---
276
+
277
+ ### Marker Component
278
+
279
+ Displays a marker on the map at specified coordinates.
280
+
281
+ <details>
282
+ <summary><strong>Props</strong></summary>
283
+
284
+ | Prop | Type | Default | Description |
285
+ |------|------|---------|-------------|
286
+ | `longitude` | `number` | Required | Longitude of the marker |
287
+ | `latitude` | `number` | Required | Latitude of the marker |
288
+ | `color` | `string` | - | Marker color |
289
+ | `draggable` | `boolean` | `false` | Enable dragging |
290
+ | `offset` | `[number, number]` | - | Pixel offset |
291
+ | `anchor` | `string` | `'center'` | Marker anchor position |
292
+ | `scale` | `number` | `1` | Marker scale |
293
+ | `rotation` | `number` | `0` | Rotation in degrees |
294
+ | `rotationAlignment` | `string` | `'auto'` | Rotation alignment mode |
295
+ | `pitchAlignment` | `string` | `'auto'` | Pitch alignment mode |
296
+ | `popup` | `Popup` | - | Popup to show on click |
297
+ | `onClick` | `(e: MarkerEvent) => void` | - | Click handler |
298
+ | `onDragStart` | `(e: MarkerDragEvent) => void` | - | Drag start handler |
299
+ | `onDrag` | `(e: MarkerDragEvent) => void` | - | Drag handler |
300
+ | `onDragEnd` | `(e: MarkerDragEvent) => void` | - | Drag end handler |
301
+
302
+ </details>
303
+
304
+ #### Example
305
+
306
+ ```tsx
307
+ import { Map, Marker } from 'react-bkoi-gl';
136
308
  import "react-bkoi-gl/styles";
309
+ import { useState } from 'react';
310
+
311
+ function MarkerExample() {
312
+ const [marker, setMarker] = useState({
313
+ lng: 90.3938,
314
+ lat: 23.8216
315
+ });
316
+
317
+ const onDragEnd = (e) => {
318
+ setMarker({
319
+ lng: e.lngLat.lng,
320
+ lat: e.lngLat.lat
321
+ });
322
+ };
323
+
324
+ return (
325
+ <Map
326
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
327
+ initialViewState={{
328
+ longitude: 90.3938,
329
+ latitude: 23.8216,
330
+ zoom: 12
331
+ }}
332
+ style={{ width: '100%', height: '100vh' }}
333
+ >
334
+ {/* Simple marker */}
335
+ <Marker longitude={90.3938} latitude={23.8216} color="red" />
336
+
337
+ {/* Draggable marker */}
338
+ <Marker
339
+ longitude={marker.lng}
340
+ latitude={marker.lat}
341
+ color="blue"
342
+ draggable
343
+ onDragEnd={onDragEnd}
344
+ />
137
345
 
138
- interface MapProps {
139
- longitude: number;
140
- latitude: number;
346
+ {/* Custom marker with React children */}
347
+ <Marker longitude={90.40} latitude={23.83}>
348
+ <div style={{
349
+ backgroundColor: '#fff',
350
+ padding: '5px 10px',
351
+ borderRadius: '5px',
352
+ boxShadow: '0 2px 5px rgba(0,0,0,0.3)'
353
+ }}>
354
+ Custom Marker
355
+ </div>
356
+ </Marker>
357
+ </Map>
358
+ );
141
359
  }
360
+ ```
142
361
 
143
- const App: React.FC = () => {
144
- const BARIKOI_API_KEY = 'YOUR_BARIKOI_API_KEY_HERE';
145
- const mapStyle = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`;
146
- const mapContainer = useRef<HTMLDivElement>(null);
147
- const mapRef = useRef<MapRef>(null);
148
- const initialViewState = {
149
- longitude: 90.36402,
150
- latitude: 23.823731,
151
- minZoom: 4,
152
- maxZoom: 22,
153
- zoom: 13,
154
- bearing: 0,
155
- pitch: 0,
156
- antialias: true,
362
+ ---
363
+
364
+ ### Popup Component
365
+
366
+ Displays a popup with custom content at specified coordinates.
367
+
368
+ <details>
369
+ <summary><strong>Props</strong></summary>
370
+
371
+ | Prop | Type | Default | Description |
372
+ |------|------|---------|-------------|
373
+ | `longitude` | `number` | Required | Longitude of the popup |
374
+ | `latitude` | `number` | Required | Latitude of the popup |
375
+ | `anchor` | `string` | - | Popup anchor position |
376
+ | `offset` | `number \| [number, number]` | - | Pixel offset |
377
+ | `className` | `string` | - | CSS class name |
378
+ | `maxWidth` | `string` | `'240px'` | Maximum width |
379
+ | `closeButton` | `boolean` | `true` | Show close button |
380
+ | `closeOnClick` | `boolean` | `true` | Close on map click |
381
+ | `onOpen` | `() => void` | - | Open handler |
382
+ | `onClose` | `() => void` | - | Close handler |
383
+ | `children` | `ReactNode` | - | Popup content |
384
+
385
+ </details>
386
+
387
+ #### Example
388
+
389
+ ```tsx
390
+ import { Map, Marker, Popup } from 'react-bkoi-gl';
391
+ import "react-bkoi-gl/styles";
392
+ import { useState } from 'react';
393
+
394
+ function PopupExample() {
395
+ const [showPopup, setShowPopup] = useState(true);
396
+
397
+ return (
398
+ <Map
399
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
400
+ initialViewState={{
401
+ longitude: 90.3938,
402
+ latitude: 23.8216,
403
+ zoom: 12
404
+ }}
405
+ style={{ width: '100%', height: '100vh' }}
406
+ >
407
+ {/* Standalone popup */}
408
+ {showPopup && (
409
+ <Popup
410
+ longitude={90.3938}
411
+ latitude={23.8216}
412
+ anchor="bottom"
413
+ onClose={() => setShowPopup(false)}
414
+ >
415
+ <div>
416
+ <h3>Dhaka</h3>
417
+ <p>Capital of Bangladesh</p>
418
+ </div>
419
+ </Popup>
420
+ )}
421
+
422
+ {/* Marker with attached popup */}
423
+ <Marker longitude={90.40} latitude={23.83} color="red">
424
+ <Popup>
425
+ <div>Popup attached to marker</div>
426
+ </Popup>
427
+ </Marker>
428
+ </Map>
429
+ );
430
+ }
431
+ ```
432
+
433
+ ---
434
+
435
+ ### Source Component
436
+
437
+ Defines a data source for the map. Supports GeoJSON, vector tiles, raster tiles, image, and video sources.
438
+
439
+ <details>
440
+ <summary><strong>Props</strong></summary>
441
+
442
+ | Prop | Type | Description |
443
+ |------|------|-------------|
444
+ | `id` | `string` | Unique source identifier |
445
+ | `type` | `string` | Source type: `'geojson'`, `'vector'`, `'raster'`, `'image'`, `'video'` |
446
+ | `data` | `object \| string` | GeoJSON data or URL (for geojson type) |
447
+ | `url` | `string` | Tile URL (for vector/raster) |
448
+ | `tiles` | `string[]` | Tile URLs array |
449
+ | `tileSize` | `number` | Tile size in pixels |
450
+ | `coordinates` | `array` | Image coordinates (for image type) |
451
+ | `children` | `ReactNode` | Layer components using this source |
452
+
453
+ </details>
454
+
455
+ #### Example
456
+
457
+ ```tsx
458
+ import { Map, Source, Layer } from 'react-bkoi-gl';
459
+ import "react-bkoi-gl/styles";
460
+
461
+ function SourceExample() {
462
+ const geojsonData = {
463
+ type: 'FeatureCollection',
464
+ features: [
465
+ {
466
+ type: 'Feature',
467
+ properties: { name: 'Point A' },
468
+ geometry: {
469
+ type: 'Point',
470
+ coordinates: [90.3938, 23.8216]
471
+ }
472
+ },
473
+ {
474
+ type: 'Feature',
475
+ properties: { name: 'Point B' },
476
+ geometry: {
477
+ type: 'Point',
478
+ coordinates: [90.40, 23.83]
479
+ }
480
+ }
481
+ ]
482
+ };
483
+
484
+ const lineData = {
485
+ type: 'Feature',
486
+ properties: {},
487
+ geometry: {
488
+ type: 'LineString',
489
+ coordinates: [
490
+ [90.3938, 23.8216],
491
+ [90.40, 23.83],
492
+ [90.41, 23.84]
493
+ ]
494
+ }
495
+ };
496
+
497
+ const polygonData = {
498
+ type: 'Feature',
499
+ properties: { name: 'Polygon Area' },
500
+ geometry: {
501
+ type: 'Polygon',
502
+ coordinates: [[
503
+ [90.39, 23.82],
504
+ [90.41, 23.82],
505
+ [90.41, 23.84],
506
+ [90.39, 23.84],
507
+ [90.39, 23.82]
508
+ ]]
509
+ }
157
510
  };
158
511
 
159
512
  return (
160
- <div ref={mapContainer} style={containerStyles}>
161
- <Map
162
- ref={mapRef}
163
- mapStyle={mapStyle}
164
- style={{ width: "100%", height: "100%" }}
165
- initialViewState={initialViewState}
166
- doubleClickZoom={false}
167
- dragRotate={false}
513
+ <Map
514
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
515
+ initialViewState={{
516
+ longitude: 90.40,
517
+ latitude: 23.83,
518
+ zoom: 12
519
+ }}
520
+ style={{ width: '100%', height: '100vh' }}
521
+ >
522
+ {/* GeoJSON point source */}
523
+ <Source id="points" type="geojson" data={geojsonData}>
524
+ <Layer
525
+ id="points-layer"
526
+ type="circle"
527
+ paint={{
528
+ 'circle-radius': 10,
529
+ 'circle-color': '#007cbf'
530
+ }}
531
+ />
532
+ </Source>
533
+
534
+ {/* GeoJSON line source */}
535
+ <Source id="line" type="geojson" data={lineData}>
536
+ <Layer
537
+ id="line-layer"
538
+ type="line"
539
+ paint={{
540
+ 'line-width': 3,
541
+ 'line-color': '#ff0000'
542
+ }}
543
+ />
544
+ </Source>
545
+
546
+ {/* GeoJSON polygon source */}
547
+ <Source id="polygon" type="geojson" data={polygonData}>
548
+ <Layer
549
+ id="polygon-fill"
550
+ type="fill"
551
+ paint={{
552
+ 'fill-color': '#088',
553
+ 'fill-opacity': 0.4
554
+ }}
555
+ />
556
+ <Layer
557
+ id="polygon-outline"
558
+ type="line"
559
+ paint={{
560
+ 'line-color': '#000',
561
+ 'line-width': 2
562
+ }}
563
+ />
564
+ </Source>
565
+
566
+ {/* Raster tile source */}
567
+ <Source
568
+ id="satellite"
569
+ type="raster"
570
+ tiles={['https://example.com/tiles/{z}/{x}/{y}.png']}
571
+ tileSize={256}
168
572
  >
169
- <Marker longitude={90.36402} latitude={23.823731} color="red" />
170
- <Popup longitude={90.36402} latitude={23.823731}>
171
- <div>Hello, Barikoi!</div>
172
- </Popup>
173
- <Source
174
- id="points"
175
- type="geojson"
176
- data={{
177
- type: 'FeatureCollection',
178
- features: [
179
- {
180
- type: 'Feature',
181
- properties: {},
182
- geometry: { type: 'Point', coordinates: [90.36402, 23.823731] }
183
- }
184
- ]
573
+ <Layer id="satellite-layer" type="raster" />
574
+ </Source>
575
+ </Map>
576
+ );
577
+ }
578
+ ```
579
+
580
+ ---
581
+
582
+ ### Layer Component
583
+
584
+ Renders data from a source on the map. Supports all MapLibre layer types.
585
+
586
+ <details>
587
+ <summary><strong>Props</strong></summary>
588
+
589
+ | Prop | Type | Description |
590
+ |------|------|-------------|
591
+ | `id` | `string` | Unique layer identifier |
592
+ | `type` | `string` | Layer type: `'fill'`, `'line'`, `'circle'`, `'symbol'`, `'raster'`, `'heatmap'`, `'hillshade'`, `'background'` |
593
+ | `source` | `string` | Source ID (inherited from parent Source) |
594
+ | `source-layer` | `string` | Source layer (for vector sources) |
595
+ | `paint` | `object` | Paint properties |
596
+ | `layout` | `object` | Layout properties |
597
+ | `filter` | `array` | Filter expression |
598
+ | `minzoom` | `number` | Minimum zoom level |
599
+ | `maxzoom` | `number` | Maximum zoom level |
600
+ | `beforeId` | `string` | Insert before this layer ID |
601
+
602
+ </details>
603
+
604
+ #### Example
605
+
606
+ ```tsx
607
+ import { Map, Source, Layer } from 'react-bkoi-gl';
608
+ import "react-bkoi-gl/styles";
609
+
610
+ function LayerExample() {
611
+ const cities = {
612
+ type: 'FeatureCollection',
613
+ features: [
614
+ { type: 'Feature', properties: { name: 'Dhaka', population: 21000000 }, geometry: { type: 'Point', coordinates: [90.3938, 23.8216] } },
615
+ { type: 'Feature', properties: { name: 'Chittagong', population: 4000000 }, geometry: { type: 'Point', coordinates: [91.8317, 22.3569] } },
616
+ { type: 'Feature', properties: { name: 'Khulna', population: 1500000 }, geometry: { type: 'Point', coordinates: [89.5555, 22.8456] } }
617
+ ]
618
+ };
619
+
620
+ return (
621
+ <Map
622
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
623
+ initialViewState={{
624
+ longitude: 90.3938,
625
+ latitude: 23.8216,
626
+ zoom: 6
627
+ }}
628
+ style={{ width: '100%', height: '100vh' }}
629
+ >
630
+ <Source id="cities" type="geojson" data={cities}>
631
+ {/* Circle layer with data-driven styling */}
632
+ <Layer
633
+ id="cities-circles"
634
+ type="circle"
635
+ paint={{
636
+ 'circle-radius': ['*', 0.000001, ['get', 'population']],
637
+ 'circle-color': [
638
+ 'interpolate',
639
+ ['linear'],
640
+ ['get', 'population'],
641
+ 1000000, '#51bbd6',
642
+ 5000000, '#f1f075',
643
+ 20000000, '#f28cb1'
644
+ ],
645
+ 'circle-opacity': 0.8
185
646
  }}
186
647
  />
648
+
649
+ {/* Symbol layer for labels */}
187
650
  <Layer
188
- id="points-layer"
651
+ id="cities-labels"
652
+ type="symbol"
653
+ layout={{
654
+ 'text-field': ['get', 'name'],
655
+ 'text-font': ['Open Sans Regular'],
656
+ 'text-offset': [0, 2],
657
+ 'text-anchor': 'top'
658
+ }}
659
+ paint={{
660
+ 'text-color': '#000',
661
+ 'text-halo-color': '#fff',
662
+ 'text-halo-width': 1
663
+ }}
664
+ />
665
+
666
+ {/* Filtered layer */}
667
+ <Layer
668
+ id="large-cities"
189
669
  type="circle"
190
- source="points"
191
- paint={{ 'circle-radius': 10, 'circle-color': '#ff0000' }}
670
+ filter={['>', ['get', 'population'], 5000000]}
671
+ paint={{
672
+ 'circle-radius': 20,
673
+ 'circle-color': '#ff0000',
674
+ 'circle-stroke-width': 2,
675
+ 'circle-stroke-color': '#fff'
676
+ }}
192
677
  />
193
- <NavigationControl position="top-right" />
194
- <FullscreenControl position="top-right" />
195
- <GeolocateControl position="top-right" />
196
- <ScaleControl position="bottom-right" />
197
- </Map>
678
+ </Source>
679
+ </Map>
680
+ );
681
+ }
682
+ ```
683
+
684
+ ---
685
+
686
+ ### Navigation Control
687
+
688
+ Adds zoom and rotation controls to the map.
689
+
690
+ <details>
691
+ <summary><strong>Props</strong></summary>
692
+
693
+ | Prop | Type | Default | Description |
694
+ |------|------|---------|-------------|
695
+ | `position` | `string` | `'top-right'` | Control position |
696
+ | `showCompass` | `boolean` | `true` | Show compass button |
697
+ | `showZoom` | `boolean` | `true` | Show zoom buttons |
698
+ | `visualizePitch` | `boolean` | `false` | Visualize pitch in compass |
699
+
700
+ </details>
701
+
702
+ #### Example
703
+
704
+ ```tsx
705
+ import { Map, NavigationControl } from 'react-bkoi-gl';
706
+ import "react-bkoi-gl/styles";
707
+
708
+ function NavigationExample() {
709
+ return (
710
+ <Map
711
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
712
+ initialViewState={{
713
+ longitude: 90.3938,
714
+ latitude: 23.8216,
715
+ zoom: 12
716
+ }}
717
+ style={{ width: '100%', height: '100vh' }}
718
+ >
719
+ <NavigationControl position="top-right" showCompass showZoom visualizePitch />
720
+ </Map>
721
+ );
722
+ }
723
+ ```
724
+
725
+ ---
726
+
727
+ ### Fullscreen Control
728
+
729
+ Adds a button to toggle fullscreen mode.
730
+
731
+ <details>
732
+ <summary><strong>Props</strong></summary>
733
+
734
+ | Prop | Type | Default | Description |
735
+ |------|------|---------|-------------|
736
+ | `position` | `string` | `'top-right'` | Control position |
737
+ | `container` | `HTMLElement` | - | Custom fullscreen container |
738
+
739
+ </details>
740
+
741
+ #### Example
742
+
743
+ ```tsx
744
+ import { Map, FullscreenControl } from 'react-bkoi-gl';
745
+ import "react-bkoi-gl/styles";
746
+
747
+ function FullscreenExample() {
748
+ return (
749
+ <Map
750
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
751
+ initialViewState={{
752
+ longitude: 90.3938,
753
+ latitude: 23.8216,
754
+ zoom: 12
755
+ }}
756
+ style={{ width: '100%', height: '100vh' }}
757
+ >
758
+ <FullscreenControl position="top-right" />
759
+ </Map>
760
+ );
761
+ }
762
+ ```
763
+
764
+ ---
765
+
766
+ ### Geolocate Control
767
+
768
+ Centers the map on the user's current location.
769
+
770
+ <details>
771
+ <summary><strong>Props</strong></summary>
772
+
773
+ | Prop | Type | Default | Description |
774
+ |------|------|---------|-------------|
775
+ | `position` | `string` | `'top-right'` | Control position |
776
+ | `positionOptions` | `object` | `{ enableHighAccuracy: true }` | Geolocation options |
777
+ | `fitBoundsOptions` | `object` | `{ maxZoom: 15 }` | Fit bounds options |
778
+ | `trackUserLocation` | `boolean` | `false` | Track user location |
779
+ | `showAccuracyCircle` | `boolean` | `true` | Show accuracy circle |
780
+ | `showUserLocation` | `boolean` | `true` | Show user location marker |
781
+ | `onGeolocate` | `(e: GeolocateResultEvent) => void` | - | Geolocate success handler |
782
+ | `onError` | `(e: GeolocateErrorEvent) => void` | - | Error handler |
783
+
784
+ </details>
785
+
786
+ #### Example
787
+
788
+ ```tsx
789
+ import { Map, GeolocateControl } from 'react-bkoi-gl';
790
+ import "react-bkoi-gl/styles";
791
+
792
+ function GeolocateExample() {
793
+ const onGeolocate = (e) => {
794
+ console.log('User location:', e.coords);
795
+ };
796
+
797
+ return (
798
+ <Map
799
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
800
+ initialViewState={{
801
+ longitude: 90.3938,
802
+ latitude: 23.8216,
803
+ zoom: 12
804
+ }}
805
+ style={{ width: '100%', height: '100vh' }}
806
+ >
807
+ <GeolocateControl
808
+ position="top-right"
809
+ trackUserLocation
810
+ showAccuracyCircle
811
+ onGeolocate={onGeolocate}
812
+ />
813
+ </Map>
814
+ );
815
+ }
816
+ ```
817
+
818
+ ---
819
+
820
+ ### Scale Control
821
+
822
+ Displays a scale bar on the map.
823
+
824
+ <details>
825
+ <summary><strong>Props</strong></summary>
826
+
827
+ | Prop | Type | Default | Description |
828
+ |------|------|---------|-------------|
829
+ | `position` | `string` | `'bottom-left'` | Control position |
830
+ | `maxWidth` | `number` | `100` | Maximum width in pixels |
831
+ | `unit` | `string` | `'metric'` | Unit: `'imperial'`, `'metric'`, or `'nautical'` |
832
+
833
+ </details>
834
+
835
+ #### Example
836
+
837
+ ```tsx
838
+ import { Map, ScaleControl } from 'react-bkoi-gl';
839
+ import "react-bkoi-gl/styles";
840
+
841
+ function ScaleExample() {
842
+ return (
843
+ <Map
844
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
845
+ initialViewState={{
846
+ longitude: 90.3938,
847
+ latitude: 23.8216,
848
+ zoom: 12
849
+ }}
850
+ style={{ width: '100%', height: '100vh' }}
851
+ >
852
+ <ScaleControl position="bottom-left" unit="metric" maxWidth={150} />
853
+ </Map>
854
+ );
855
+ }
856
+ ```
857
+
858
+ ---
859
+
860
+ ### Terrain Control
861
+
862
+ Adds terrain visualization to the map.
863
+
864
+ <details>
865
+ <summary><strong>Props</strong></summary>
866
+
867
+ | Prop | Type | Default | Description |
868
+ |------|------|---------|-------------|
869
+ | `position` | `string` | `'top-right'` | Control position |
870
+ | `source` | `string \| object` | - | Terrain source |
871
+
872
+ </details>
873
+
874
+ #### Example
875
+
876
+ ```tsx
877
+ import { Map, TerrainControl, Source, Layer } from 'react-bkoi-gl';
878
+ import "react-bkoi-gl/styles";
879
+
880
+ function TerrainExample() {
881
+ return (
882
+ <Map
883
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
884
+ initialViewState={{
885
+ longitude: 90.3938,
886
+ latitude: 23.8216,
887
+ zoom: 12,
888
+ pitch: 60
889
+ }}
890
+ style={{ width: '100%', height: '100vh' }}
891
+ >
892
+ <Source
893
+ id="terrain"
894
+ type="raster-dem"
895
+ url="mapbox://mapbox.mapbox-terrain-dem-v1"
896
+ tileSize={512}
897
+ maxzoom={14}
898
+ />
899
+ <TerrainControl source="terrain" />
900
+ </Map>
901
+ );
902
+ }
903
+ ```
904
+
905
+ ---
906
+
907
+ ### Draw Control
908
+
909
+ Adds drawing tools for creating and editing polygons, lines, and points.
910
+
911
+ <details>
912
+ <summary><strong>Props</strong></summary>
913
+
914
+ | Prop | Type | Default | Description |
915
+ |------|------|---------|-------------|
916
+ | `position` | `string` | `'top-left'` | Control position |
917
+ | `displayControlsDefault` | `boolean` | `false` | Show all controls by default |
918
+ | `controls` | `object` | `{ polygon: true, trash: true }` | Control visibility |
919
+ | `styles` | `array` | - | Custom draw styles |
920
+ | `modes` | `object` | - | Custom draw modes |
921
+ | `defaultMode` | `string` | `'simple_select'` | Default drawing mode |
922
+ | `onDrawCreate` | `(e: DrawEvent) => void` | - | Feature created handler |
923
+ | `onDrawDelete` | `(e: DrawEvent) => void` | - | Feature deleted handler |
924
+ | `onDrawUpdate` | `(e: DrawEvent) => void` | - | Feature updated handler |
925
+ | `onDrawSelectionChange` | `(e: DrawEvent) => void` | - | Selection change handler |
926
+ | `onDrawModeChange` | `(e: DrawEvent) => void` | - | Mode change handler |
927
+
928
+ </details>
929
+
930
+ #### Example
931
+
932
+ ```tsx
933
+ import { Map, DrawControl } from 'react-bkoi-gl';
934
+ import "react-bkoi-gl/styles";
935
+ import { useState } from 'react';
936
+
937
+ function DrawExample() {
938
+ const [features, setFeatures] = useState([]);
939
+
940
+ const onDrawCreate = (e) => {
941
+ console.log('Created features:', e.features);
942
+ setFeatures(e.features);
943
+ };
944
+
945
+ const onDrawUpdate = (e) => {
946
+ console.log('Updated features:', e.features);
947
+ setFeatures(e.features);
948
+ };
949
+
950
+ const onDrawDelete = (e) => {
951
+ console.log('Deleted features:', e.features);
952
+ };
953
+
954
+ return (
955
+ <Map
956
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
957
+ initialViewState={{
958
+ longitude: 90.3938,
959
+ latitude: 23.8216,
960
+ zoom: 12
961
+ }}
962
+ style={{ width: '100%', height: '100vh' }}
963
+ >
964
+ <DrawControl
965
+ position="top-left"
966
+ controls={{
967
+ polygon: true,
968
+ line_string: true,
969
+ point: true,
970
+ trash: true,
971
+ combine_features: false,
972
+ uncombine_features: false
973
+ }}
974
+ onDrawCreate={onDrawCreate}
975
+ onDrawUpdate={onDrawUpdate}
976
+ onDrawDelete={onDrawDelete}
977
+ />
978
+ </Map>
979
+ );
980
+ }
981
+ ```
982
+
983
+ ---
984
+
985
+ ### Minimap Control
986
+
987
+ Displays a small overview map for navigation.
988
+
989
+ <details>
990
+ <summary><strong>Props</strong></summary>
991
+
992
+ | Prop | Type | Default | Description |
993
+ |------|------|---------|-------------|
994
+ | `position` | `string` | `'top-right'` | Control position |
995
+ | `center` | `[number, number]` | - | Initial center coordinates |
996
+ | `zoomAdjust` | `number` | `-4` | Zoom offset from parent |
997
+ | `lockZoom` | `number` | - | Lock to specific zoom level |
998
+ | `pitchAdjust` | `boolean` | `false` | Sync pitch with parent |
999
+ | `style` | `string \| StyleSpecification` | - | Custom minimap style |
1000
+ | `containerStyle` | `object` | - | Custom container styles |
1001
+ | `toggleable` | `boolean` | `true` | Allow toggling minimap |
1002
+ | `initialMinimized` | `boolean` | `false` | Start minimized |
1003
+ | `responsive` | `boolean` | `true` | Enable responsive sizing |
1004
+ | `interactions` | `object` | - | Interaction configuration |
1005
+ | `parentRect` | `object` | - | Parent rectangle styling |
1006
+ | `onToggle` | `(isMinimized: boolean) => void` | - | Toggle callback |
1007
+
1008
+ </details>
1009
+
1010
+ #### Example
1011
+
1012
+ ```tsx
1013
+ import { Map, MinimapControl } from 'react-bkoi-gl';
1014
+ import "react-bkoi-gl/styles";
1015
+
1016
+ function MinimapExample() {
1017
+ const onToggle = (isMinimized) => {
1018
+ console.log('Minimap minimized:', isMinimized);
1019
+ };
1020
+
1021
+ return (
1022
+ <Map
1023
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1024
+ initialViewState={{
1025
+ longitude: 90.3938,
1026
+ latitude: 23.8216,
1027
+ zoom: 12
1028
+ }}
1029
+ style={{ width: '100%', height: '100vh' }}
1030
+ >
1031
+ <MinimapControl
1032
+ position="bottom-right"
1033
+ zoomAdjust={-5}
1034
+ toggleable
1035
+ initialMinimized={false}
1036
+ containerStyle={{
1037
+ width: '200px',
1038
+ height: '150px'
1039
+ }}
1040
+ parentRect={{
1041
+ linePaint: {
1042
+ 'line-color': '#FF0000',
1043
+ 'line-width': 2
1044
+ },
1045
+ fillPaint: {
1046
+ 'fill-color': '#0000FF',
1047
+ 'fill-opacity': 0.1
1048
+ }
1049
+ }}
1050
+ interactions={{
1051
+ dragPan: true,
1052
+ scrollZoom: false
1053
+ }}
1054
+ onToggle={onToggle}
1055
+ />
1056
+ </Map>
1057
+ );
1058
+ }
1059
+ ```
1060
+
1061
+ ---
1062
+
1063
+ ### Globe Control
1064
+
1065
+ Toggle between 2D map and 3D globe view (requires MapLibre GL 3.x+).
1066
+
1067
+ <details>
1068
+ <summary><strong>Props</strong></summary>
1069
+
1070
+ | Prop | Type | Default | Description |
1071
+ |------|------|---------|-------------|
1072
+ | `position` | `string` | `'top-right'` | Control position |
1073
+ | `buttonClassName` | `string` | `'maplibregl-ctrl-globe'` | Button CSS class |
1074
+ | `buttonTitle` | `string` | `'Toggle Globe View'` | Button tooltip |
1075
+ | `buttonStyle` | `CSSProperties` | - | Custom button styles |
1076
+ | `onProjectionChange` | `(isGlobe: boolean) => void` | - | Projection change handler |
1077
+
1078
+ </details>
1079
+
1080
+ #### Example
1081
+
1082
+ ```tsx
1083
+ import { Map, GlobeControl } from 'react-bkoi-gl';
1084
+ import "react-bkoi-gl/styles";
1085
+
1086
+ function GlobeExample() {
1087
+ const handleProjectionChange = (isGlobe) => {
1088
+ console.log('Globe view:', isGlobe);
1089
+ };
1090
+
1091
+ return (
1092
+ <Map
1093
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1094
+ initialViewState={{
1095
+ longitude: 90.3938,
1096
+ latitude: 23.8216,
1097
+ zoom: 12
1098
+ }}
1099
+ style={{ width: '100%', height: '100vh' }}
1100
+ >
1101
+ <GlobeControl
1102
+ position="top-right"
1103
+ onProjectionChange={handleProjectionChange}
1104
+ />
1105
+ </Map>
1106
+ );
1107
+ }
1108
+ ```
1109
+
1110
+ ---
1111
+
1112
+ ### Canvas Source
1113
+
1114
+ Render custom HTML canvas elements as map layers.
1115
+
1116
+ <details>
1117
+ <summary><strong>Props</strong></summary>
1118
+
1119
+ | Prop | Type | Description |
1120
+ |------|------|-------------|
1121
+ | `id` | `string` | Unique source identifier |
1122
+ | `coordinates` | `[[lng,lat], [lng,lat], [lng,lat], [lng,lat]]` | Corner coordinates (top-left, top-right, bottom-right, bottom-left) |
1123
+ | `canvas` | `HTMLCanvasElement` | The canvas element to render |
1124
+ | `animate` | `boolean` | Whether to animate the canvas |
1125
+ | `children` | `ReactNode` | Child Layer components |
1126
+
1127
+ </details>
1128
+
1129
+ #### Example
1130
+
1131
+ ```tsx
1132
+ import { Map, CanvasSource, Layer } from 'react-bkoi-gl';
1133
+ import "react-bkoi-gl/styles";
1134
+ import { useRef, useEffect, useState } from 'react';
1135
+
1136
+ function CanvasExample() {
1137
+ const canvasRef = useRef<HTMLCanvasElement>(null);
1138
+ const [canvasEl, setCanvasEl] = useState<HTMLCanvasElement | null>(null);
1139
+
1140
+ useEffect(() => {
1141
+ const canvas = canvasRef.current;
1142
+ if (!canvas) return;
1143
+
1144
+ const ctx = canvas.getContext('2d');
1145
+ if (ctx) {
1146
+ ctx.fillStyle = 'rgba(0, 100, 255, 0.5)';
1147
+ ctx.fillRect(0, 0, 256, 256);
1148
+ ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
1149
+ ctx.beginPath();
1150
+ ctx.arc(128, 128, 50, 0, 2 * Math.PI);
1151
+ ctx.fill();
1152
+ }
1153
+
1154
+ setCanvasEl(canvas);
1155
+ }, []);
1156
+
1157
+ return (
1158
+ <Map
1159
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1160
+ initialViewState={{
1161
+ longitude: 90.3938,
1162
+ latitude: 23.8216,
1163
+ zoom: 12
1164
+ }}
1165
+ style={{ width: '100%', height: '100vh' }}
1166
+ >
1167
+ <canvas ref={canvasRef} width={256} height={256} style={{ display: 'none' }} />
1168
+ {canvasEl && (
1169
+ <CanvasSource
1170
+ id="my-canvas"
1171
+ coordinates={[
1172
+ [90.38, 23.83],
1173
+ [90.41, 23.83],
1174
+ [90.41, 23.81],
1175
+ [90.38, 23.81]
1176
+ ]}
1177
+ canvas={canvasEl}
1178
+ animate={true}
1179
+ >
1180
+ <Layer type="raster" paint={{ 'raster-opacity': 0.8 }} />
1181
+ </CanvasSource>
1182
+ )}
1183
+ </Map>
1184
+ );
1185
+ }
1186
+ ```
1187
+
1188
+ ---
1189
+
1190
+ ## Layer Events
1191
+
1192
+ The Layer component supports interactive mouse events:
1193
+
1194
+ <details>
1195
+ <summary><strong>Available Events</strong></summary>
1196
+
1197
+ | Prop | Type | Description |
1198
+ |------|------|-------------|
1199
+ | `onClick` | `(e: MapLayerMouseEvent) => void` | Fired when layer is clicked |
1200
+ | `onMouseEnter` | `(e: MapLayerMouseEvent) => void` | Fired when mouse enters layer |
1201
+ | `onMouseLeave` | `() => void` | Fired when mouse leaves layer |
1202
+ | `onMouseMove` | `(e: MapLayerMouseEvent) => void` | Fired when mouse moves over layer |
1203
+ | `onMouseDown` | `(e: MapLayerMouseEvent) => void` | Fired on mouse button press |
1204
+ | `onMouseUp` | `(e: MapLayerMouseEvent) => void` | Fired on mouse button release |
1205
+ | `onContextMenu` | `(e: MapLayerMouseEvent) => void` | Fired on right-click |
1206
+ | `onDoubleClick` | `(e: MapLayerMouseEvent) => void` | Fired on double-click |
1207
+
1208
+ </details>
1209
+
1210
+ #### Example
1211
+
1212
+ ```tsx
1213
+ import { Map, Source, Layer } from 'react-bkoi-gl';
1214
+ import "react-bkoi-gl/styles";
1215
+ import { useState } from 'react';
1216
+
1217
+ function InteractiveLayerExample() {
1218
+ const [hoveredFeature, setHoveredFeature] = useState(null);
1219
+
1220
+ const geojsonData = {
1221
+ type: 'FeatureCollection',
1222
+ features: [
1223
+ { type: 'Feature', properties: { name: 'Dhaka' }, geometry: { type: 'Point', coordinates: [90.3938, 23.8216] } }
1224
+ ]
1225
+ };
1226
+
1227
+ return (
1228
+ <Map
1229
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1230
+ initialViewState={{
1231
+ longitude: 90.3938,
1232
+ latitude: 23.8216,
1233
+ zoom: 12
1234
+ }}
1235
+ style={{ width: '100%', height: '100vh' }}
1236
+ >
1237
+ <Source id="places" type="geojson" data={geojsonData}>
1238
+ <Layer
1239
+ id="places-layer"
1240
+ type="circle"
1241
+ paint={{
1242
+ 'circle-radius': hoveredFeature ? 12 : 8,
1243
+ 'circle-color': hoveredFeature ? '#FF0000' : '#007cbf'
1244
+ }}
1245
+ onClick={(e) => {
1246
+ console.log('Clicked:', e.features[0].properties.name);
1247
+ }}
1248
+ onMouseEnter={(e) => {
1249
+ setHoveredFeature(e.features[0]);
1250
+ }}
1251
+ onMouseLeave={() => {
1252
+ setHoveredFeature(null);
1253
+ }}
1254
+ />
1255
+ </Source>
1256
+ </Map>
1257
+ );
1258
+ }
1259
+ ```
1260
+
1261
+ ---
1262
+
1263
+ ## Hooks
1264
+
1265
+ ### useMap Hook
1266
+
1267
+ Access map instances from any component within the MapProvider.
1268
+
1269
+ #### Example
1270
+
1271
+ ```tsx
1272
+ import { Map, useMap, MapProvider } from 'react-bkoi-gl';
1273
+ import "react-bkoi-gl/styles";
1274
+
1275
+ function MapButtons() {
1276
+ const { current: map } = useMap();
1277
+
1278
+ const zoomIn = () => {
1279
+ map?.zoomIn();
1280
+ };
1281
+
1282
+ const zoomOut = () => {
1283
+ map?.zoomOut();
1284
+ };
1285
+
1286
+ const flyTo = () => {
1287
+ map?.flyTo({
1288
+ center: [90.40, 23.83],
1289
+ zoom: 15,
1290
+ duration: 2000
1291
+ });
1292
+ };
1293
+
1294
+ return (
1295
+ <div style={{ position: 'absolute', top: 10, left: 10, zIndex: 1 }}>
1296
+ <button onClick={zoomIn}>Zoom In</button>
1297
+ <button onClick={zoomOut}>Zoom Out</button>
1298
+ <button onClick={flyTo}>Fly to Location</button>
198
1299
  </div>
199
1300
  );
200
- };
1301
+ }
1302
+
1303
+ function App() {
1304
+ return (
1305
+ <MapProvider>
1306
+ <Map
1307
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1308
+ initialViewState={{
1309
+ longitude: 90.3938,
1310
+ latitude: 23.8216,
1311
+ zoom: 12
1312
+ }}
1313
+ style={{ width: '100%', height: '100vh' }}
1314
+ />
1315
+ <MapButtons />
1316
+ </MapProvider>
1317
+ );
1318
+ }
1319
+ ```
1320
+
1321
+ ---
1322
+
1323
+ ### useControl Hook
1324
+
1325
+ Create custom map controls.
201
1326
 
202
- // JSX Styles
203
- const containerStyles: React.CSSProperties = {
204
- width: "100%",
205
- height: "100vh",
206
- minHeight: "400px",
207
- overflow: "hidden",
208
- };
1327
+ #### Example
209
1328
 
210
- export default App;
1329
+ ```tsx
1330
+ import { Map, useControl } from 'react-bkoi-gl';
1331
+ import { useControl as useMapControl } from 'react-bkoi-gl';
1332
+ import "react-bkoi-gl/styles";
1333
+
1334
+ class CustomControl {
1335
+ onAdd(map) {
1336
+ this.map = map;
1337
+ this.container = document.createElement('div');
1338
+ this.container.className = 'custom-control';
1339
+ this.container.textContent = 'Custom Control';
1340
+ this.container.style.cssText = `
1341
+ background: white;
1342
+ padding: 10px;
1343
+ border-radius: 4px;
1344
+ box-shadow: 0 0 0 2px rgba(0,0,0,0.1);
1345
+ `;
1346
+ return this.container;
1347
+ }
1348
+
1349
+ onRemove() {
1350
+ this.container.remove();
1351
+ }
1352
+ }
1353
+
1354
+ function CustomControlComponent() {
1355
+ useControl(() => new CustomControl(), { position: 'top-left' });
1356
+ return null;
1357
+ }
1358
+
1359
+ function App() {
1360
+ return (
1361
+ <Map
1362
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1363
+ initialViewState={{
1364
+ longitude: 90.3938,
1365
+ latitude: 23.8216,
1366
+ zoom: 12
1367
+ }}
1368
+ style={{ width: '100%', height: '100vh' }}
1369
+ >
1370
+ <CustomControlComponent />
1371
+ </Map>
1372
+ );
1373
+ }
211
1374
  ```
212
1375
 
213
- ## Components
1376
+ ---
214
1377
 
215
- Here is a list of all available components in `react-bkoi-gl`:
216
-
217
- | Component | Description |
218
- |---------------------|-----------------------------------------------------------------------------|
219
- | `Map` | The core component for rendering a Barikoi map. Must be the parent of all other components. |
220
- | `Marker` | Displays a marker on the map at specified coordinates. |
221
- | `Popup` | Displays a popup with custom content at specified coordinates. |
222
- | `Layer` | Adds a custom layer to the map. |
223
- | `Source` | Defines a data source for the map. |
224
- | `NavigationControl` | Adds zoom and rotation controls. |
225
- | `FullscreenControl` | Adds a button to toggle fullscreen mode. |
226
- | `GeolocateControl` | Centers the map on the user's location. |
227
- | `ScaleControl` | Displays a scale bar. |
228
- | `TerrainControl` | Adds terrain control to the map. |
229
- | `useMap` | Custom hook for managing the map instance. |
230
- | `useControl` | Custom hook for managing map controls. |
231
-
232
- ## Get Barikoi API key
1378
+ ## Events
233
1379
 
234
- To access Barikoi's API services, you need to:
235
- 1. Register on [Barikoi Developer Dashboard](https://developer.barikoi.com/register).
236
- 2. Verify with your phone number.
237
- 3. Claim your API key.
1380
+ The Map component supports various event callbacks:
1381
+
1382
+ <details>
1383
+ <summary><strong>Available Events</strong></summary>
238
1384
 
239
- Once registered, you'll be able to access the full suite of Barikoi API services. If you exceed the free usage limits, you'll need to subscribe to a paid plan.
1385
+ ### Mouse Events
1386
+ - `onClick` - Map click
1387
+ - `onDblClick` - Double click
1388
+ - `onMouseDown` - Mouse down
1389
+ - `onMouseUp` - Mouse up
1390
+ - `onMouseMove` - Mouse move
1391
+ - `onMouseEnter` - Mouse enter
1392
+ - `onMouseLeave` - Mouse leave
1393
+ - `onMouseOver` - Mouse over
1394
+ - `onMouseOut` - Mouse out
1395
+ - `onContextMenu` - Right click
240
1396
 
241
- ## Learning Resources
242
- * [Barikoi API Documentation](https://docs.barikoi.com/docs/maps-api)
1397
+ ### Touch Events
1398
+ - `onTouchStart` - Touch start
1399
+ - `onTouchEnd` - Touch end
1400
+ - `onTouchMove` - Touch move
1401
+ - `onTouchCancel` - Touch cancel
1402
+
1403
+ ### Movement Events
1404
+ - `onMoveStart` - Movement start
1405
+ - `onMove` - Movement
1406
+ - `onMoveEnd` - Movement end
1407
+ - `onDragStart` - Drag start
1408
+ - `onDrag` - Drag
1409
+ - `onDragEnd` - Drag end
1410
+ - `onZoomStart` - Zoom start
1411
+ - `onZoom` - Zoom
1412
+ - `onZoomEnd` - Zoom end
1413
+ - `onRotateStart` - Rotation start
1414
+ - `onRotate` - Rotation
1415
+ - `onRotateEnd` - Rotation end
1416
+ - `onPitchStart` - Pitch start
1417
+ - `onPitch` - Pitch
1418
+ - `onPitchEnd` - Pitch end
1419
+
1420
+ ### Map State Events
1421
+ - `onLoad` - Map loaded
1422
+ - `onRender` - Frame rendered
1423
+ - `onIdle` - Map idle
1424
+ - `onError` - Error occurred
1425
+ - `onResize` - Map resized
1426
+ - `onRemove` - Map removed
1427
+ - `onData` - Data loaded
1428
+ - `onStyleData` - Style data loaded
1429
+ - `onSourceData` - Source data loaded
1430
+
1431
+ </details>
1432
+
1433
+ ### Event Example
1434
+
1435
+ ```tsx
1436
+ import { Map, Marker } from 'react-bkoi-gl';
1437
+ import "react-bkoi-gl/styles";
1438
+ import { useState } from 'react';
1439
+
1440
+ function EventExample() {
1441
+ const [center, setCenter] = useState({ lng: 90.3938, lat: 23.8216 });
1442
+
1443
+ const onClick = (e) => {
1444
+ console.log('Clicked at:', e.lngLat);
1445
+ setCenter({ lng: e.lngLat.lng, lat: e.lngLat.lat });
1446
+ };
1447
+
1448
+ const onMoveEnd = (e) => {
1449
+ console.log('Move ended, viewState:', e.viewState);
1450
+ };
1451
+
1452
+ const onLoad = (e) => {
1453
+ console.log('Map loaded!');
1454
+ };
1455
+
1456
+ return (
1457
+ <Map
1458
+ mapStyle={`https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`}
1459
+ initialViewState={{
1460
+ longitude: 90.3938,
1461
+ latitude: 23.8216,
1462
+ zoom: 12
1463
+ }}
1464
+ style={{ width: '100%', height: '100vh' }}
1465
+ onClick={onClick}
1466
+ onMoveEnd={onMoveEnd}
1467
+ onLoad={onLoad}
1468
+ >
1469
+ <Marker longitude={center.lng} latitude={center.lat} color="red" />
1470
+ </Map>
1471
+ );
1472
+ }
1473
+ ```
1474
+
1475
+ ---
1476
+
1477
+ ## MapRef Methods
1478
+
1479
+ Access the underlying map instance through the ref:
1480
+
1481
+ <details>
1482
+ <summary><strong>Available Methods</strong></summary>
1483
+
1484
+ ```tsx
1485
+ const mapRef = useRef<MapRef>(null);
1486
+
1487
+ // Get the underlying MapLibre instance
1488
+ const map = mapRef.current?.getMap();
1489
+
1490
+ // Common methods:
1491
+ map.getCenter() // Get map center
1492
+ map.getZoom() // Get zoom level
1493
+ map.getBearing() // Get bearing
1494
+ map.getPitch() // Get pitch
1495
+ map.getBounds() // Get bounds
1496
+
1497
+ map.setCenter([lng, lat]) // Set center
1498
+ map.setZoom(zoom) // Set zoom
1499
+ map.setBearing(bearing) // Set bearing
1500
+ map.setPitch(pitch) // Set pitch
1501
+
1502
+ map.flyTo(options) // Fly to location
1503
+ map.jumpTo(options) // Jump to location
1504
+ map.easeTo(options) // Ease to location
1505
+
1506
+ map.zoomIn() // Zoom in
1507
+ map.zoomOut() // Zoom out
1508
+
1509
+ map.resize() // Resize map
1510
+ map.remove() // Remove map
1511
+ ```
1512
+
1513
+ </details>
1514
+
1515
+ ---
1516
+
1517
+ ## Styling
1518
+
1519
+ The library uses MapLibre GL JS styles. Import the styles in your application:
1520
+
1521
+ ```tsx
1522
+ import "react-bkoi-gl/styles";
1523
+ ```
1524
+
1525
+ ### Available Map Styles
1526
+
1527
+ - `osm-liberty` - Default street style
1528
+ - `osm_barikoi_v2` - Barikoi street style
1529
+
1530
+ ```tsx
1531
+ const mapStyle = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`;
1532
+ const mapStyle = `https://map.barikoi.com/styles/osm_barikoi_v2/style.json?key=${API_KEY}`;
1533
+ ```
1534
+
1535
+ ---
1536
+
1537
+ ## TypeScript
1538
+
1539
+ Full TypeScript support is included. All types are exported:
1540
+
1541
+ ```tsx
1542
+ import type {
1543
+ MapProps,
1544
+ MapRef,
1545
+ MarkerProps,
1546
+ PopupProps,
1547
+ SourceProps,
1548
+ CanvasSourceProps,
1549
+ LayerProps,
1550
+ MapLayerMouseEvent,
1551
+ ViewStateChangeEvent,
1552
+ DrawControlProps,
1553
+ GlobeControlProps,
1554
+ MinimapControlOptions
1555
+ } from 'react-bkoi-gl';
1556
+ ```
1557
+
1558
+ ---
1559
+
1560
+ ## Documentation & Resources
1561
+
1562
+ - [Barikoi API Documentation](https://docs.barikoi.com/docs/maps-api)
1563
+ - [Barikoi Business API](https://docs.barikoi.com/api)
1564
+ - [MapLibre GL JS Docs](https://maplibre.org/maplibre-native/ios/latest/documentation/maplibre/)
1565
+ - [Interactive Examples](https://docs.barikoi.com/examples)
1566
+
1567
+ ---
243
1568
 
244
1569
  ## License
245
- This library is licensed under the MIT License. See the [LICENSE](https://www.npmjs.com/package/LICENSE) file for details.
1570
+
1571
+ This library is licensed under the MIT License. See the [LICENSE](https://github.com/barikoi/react-bkoi-gl/blob/master/LICENSE) file for details.
246
1572
 
247
1573
  ## Support
248
- For any issues or questions, please contact [support@barikoi.com](mailto:support@barikoi.com).
1574
+
1575
+ For issues or questions, contact [support@barikoi.com](mailto:support@barikoi.com).
249
1576
 
250
1577
  <img src="https://docs.barikoi.com/img/barikoi-logo-black.svg" height="30" />