Migrating from Google Maps to Barikoi Maps
This guide provides a complete step-by-step process to migrate your web application from Google Maps JavaScript API to Barikoi Maps.
Overview of Changes
When migrating from Google Maps to Barikoi, you'll need to make the following key changes:
- Replace script/API loading mechanism
- Update map initialization code
- Replace API key references
- Update coordinate format (LatLng objects -> [lng, lat] arrays)
- Migrate markers, popups, and overlays
- Update geocoding and places services
- Migrate routing/directions services
- Update event listeners
Step-by-Step Migration Guide
1. Update Script Loading
Before:
<script
async
defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places,geometry"
></script>
After:
<link
rel="stylesheet"
href="https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css"
/>
<script src="https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js"></script>
2. Map Initialization
Before:
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 23.8103, lng: 90.4125 },
zoom: 12,
mapTypeId: "roadmap",
});
}
After:
const BARIKOI_API_KEY = "YOUR_BARIKOI_API_KEY";
// Barikoi map style URL with API key
const BARIKOI_STYLE_URL = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`;
const map = new bkoigl.Map({
container: "map",
style: BARIKOI_STYLE_URL,
center: [90.4125, 23.8103], // [longitude, latitude]
zoom: 12,
});
Important:
- Barikoi uses
[longitude, latitude]format, while previous implementations used{lat, lng}objects.- You must provide an explicit
styleURL with your API key for the map to load.
3. API Keys
- Barikoi API Key: Obtain from https://developer.barikoi.com/login
- The same API key is used for:
- Map display (via style URL)
- Geocoding/routing services (via API endpoints)
Available Map Styles
// Light style (recommended)
const STYLE_URL = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${API_KEY}`;
// Barikoi Light
const STYLE_URL = `https://map.barikoi.com/styles/barikoi-light/style.json?key=${API_KEY}`;
// Barikoi Dark
const STYLE_URL = `https://map.barikoi.com/styles/barikoi-dark/style.json?key=${API_KEY}`;
4. Markers
Before:
const marker = new google.maps.Marker({
position: { lat: 23.8103, lng: 90.4125 },
map: map,
title: "Dhaka",
icon: "custom-icon.png",
});
marker.addListener("click", () => {
console.log("Marker clicked");
});
After:
const marker = new bkoigl.Marker({
color: "#FF0000", // Optional: custom color
})
.setLngLat([90.4125, 23.8103])
.addTo(map);
marker.getElement().addEventListener("click", () => {
console.log("Marker clicked");
});
Custom Marker with HTML Element
Before:
const marker = new google.maps.Marker({
position: { lat: 23.8103, lng: 90.4125 },
map: map,
icon: {
url: "custom-marker.png",
scaledSize: new google.maps.Size(40, 40),
},
});
After:
const el = document.createElement("div");
el.className = "custom-marker";
el.style.backgroundImage = "url(custom-marker.png)";
el.style.width = "40px";
el.style.height = "40px";
el.style.backgroundSize = "cover";
const marker = new bkoigl.Marker({ element: el })
.setLngLat([90.4125, 23.8103])
.addTo(map);
5. Info Windows / Popups
Before:
const infoWindow = new google.maps.InfoWindow({
content: "<h3>Hello World!</h3><p>Welcome to Dhaka</p>",
position: { lat: 23.8103, lng: 90.4125 },
});
infoWindow.open(map, marker);
marker.addListener("click", () => {
infoWindow.open(map, marker);
});
After:
const popup = new bkoigl.Popup({ offset: 25 })
.setLngLat([90.4125, 23.8103])
.setHTML("<h3>Hello World!</h3><p>Welcome to Dhaka</p>");
marker.setPopup(popup);
// Popup opens on marker click by default
// To open programmatically:
popup.addTo(map);
6. Event Listeners
Before:
map.addListener("click", (event) => {
const lat = event.latLng.lat();
const lng = event.latLng.lng();
console.log(`Clicked at: ${lat}, ${lng}`);
});
map.addListener("zoom_changed", () => {
console.log("Zoom:", map.getZoom());
});
map.addListener("bounds_changed", () => {
const bounds = map.getBounds();
});
After:
map.on("click", (event) => {
const { lng, lat } = event.lngLat;
console.log(`Clicked at: ${lat}, ${lng}`);
});
map.on("zoom", () => {
console.log("Zoom:", map.getZoom());
});
map.on("moveend", () => {
const bounds = map.getBounds();
});
Event Name Mapping
| Previous Event | Barikoi Event |
|---|---|
| click | click |
| dblclick | dblclick |
| mousemove | mousemove |
| mouseenter | mouseenter |
| mouseleave | mouseleave |
| zoom_changed | zoom |
| bounds_changed | moveend |
| dragstart | dragstart |
| drag | drag |
| dragend | dragend |
| idle | idle |
| tilesloaded | load |
| center_changed | move |
| heading_changed | rotate |
| tilt_changed | pitch |
7. Map Controls and Options
Before:
const map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 23.8103, lng: 90.4125 },
zoom: 12,
zoomControl: true,
mapTypeControl: false,
streetViewControl: false,
fullscreenControl: true,
gestureHandling: "greedy",
});
After:
const BARIKOI_API_KEY = "YOUR_BARIKOI_API_KEY";
const BARIKOI_STYLE_URL = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`;
const map = new bkoigl.Map({
container: "map",
style: BARIKOI_STYLE_URL,
center: [90.4125, 23.8103],
zoom: 12,
minZoom: 5,
maxZoom: 18,
pitch: 0,
bearing: 0,
attributionControl: true,
});
// Add navigation control (zoom buttons + compass)
map.addControl(new bkoigl.NavigationControl(), "top-right");
// Add fullscreen control
map.addControl(new bkoigl.FullscreenControl(), "top-right");
// Add geolocation control
map.addControl(new bkoigl.GeolocateControl(), "top-right");
// Add scale control
map.addControl(new bkoigl.ScaleControl(), "bottom-left");
8. Geocoding (Address to Coordinates)
Before:
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ address: "Gulshan, Dhaka" }, (results, status) => {
if (status === "OK") {
const location = results[0].geometry.location;
console.log(location.lat(), location.lng());
}
});
After:
const barikoiApiKey = "YOUR_BARIKOI_API_KEY";
async function geocodeAddress(address) {
const response = await fetch(
`https://barikoi.xyz/v1/api/search/autocomplete/${barikoiApiKey}/place?q=${encodeURIComponent(
address
)}`
);
const data = await response.json();
if (data.places && data.places.length > 0) {
const place = data.places[0];
console.log(place.latitude, place.longitude);
return { lat: place.latitude, lng: place.longitude };
}
return null;
}
geocodeAddress("Gulshan, Dhaka");
9. Reverse Geocoding (Coordinates to Address)
Before:
const geocoder = new google.maps.Geocoder();
geocoder.geocode(
{ location: { lat: 23.8103, lng: 90.4125 } },
(results, status) => {
if (status === "OK" && results[0]) {
console.log(results[0].formatted_address);
}
}
);
After:
const barikoiApiKey = "YOUR_BARIKOI_API_KEY";
async function reverseGeocode(lat, lng) {
const response = await fetch(
`https://barikoi.xyz/v2/api/search/reverse/geocode?api_key=${barikoiApiKey}&longitude=${lng}&latitude=${lat}&district=true&post_code=true&sub_district=true&address=true&area=true`
);
const data = await response.json();
if (data && data.place) {
console.log(data.place.address);
return data.place;
}
return null;
}
reverseGeocode(23.8103, 90.4125);
10. Places Autocomplete
Before:
const input = document.getElementById("search-input");
const autocomplete = new google.maps.places.Autocomplete(input, {
types: ["geocode"],
componentRestrictions: { country: "bd" },
});
autocomplete.addListener("place_changed", () => {
const place = autocomplete.getPlace();
if (place.geometry) {
map.setCenter(place.geometry.location);
map.setZoom(16);
}
});
After:
const barikoiApiKey = "YOUR_BARIKOI_API_KEY";
const input = document.getElementById("search-input");
const resultsContainer = document.getElementById("search-results");
let debounceTimer;
input.addEventListener("input", (e) => {
clearTimeout(debounceTimer);
const query = e.target.value.trim();
if (query.length < 3) {
resultsContainer.innerHTML = "";
return;
}
debounceTimer = setTimeout(async () => {
const response = await fetch(
`https://barikoi.xyz/v1/api/search/autocomplete/${barikoiApiKey}/place?q=${encodeURIComponent(
query
)}`
);
const data = await response.json();
resultsContainer.innerHTML = "";
if (data.places && data.places.length > 0) {
data.places.forEach((place) => {
const item = document.createElement("div");
item.className = "autocomplete-item";
item.textContent = place.address;
item.addEventListener("click", () => {
input.value = place.address;
resultsContainer.innerHTML = "";
map.flyTo({
center: [place.longitude, place.latitude],
zoom: 16,
});
});
resultsContainer.appendChild(item);
});
}
}, 300);
});
11. Directions / Routing
Before:
const directionsService = new google.maps.DirectionsService();
const directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
directionsService.route(
{
origin: { lat: 23.8103, lng: 90.4125 },
destination: { lat: 23.7465, lng: 90.3763 },
travelMode: google.maps.TravelMode.DRIVING,
},
(result, status) => {
if (status === "OK") {
directionsRenderer.setDirections(result);
}
}
);
After:
const barikoiApiKey = "YOUR_BARIKOI_API_KEY";
async function getRoute(origin, destination) {
const response = await fetch(
`https://barikoi.xyz/v2/api/route/detail?api_key=${barikoiApiKey}&origin_lng=${origin[0]}&origin_lat=${origin[1]}&destination_lng=${destination[0]}&destination_lat=${destination[1]}`
);
const data = await response.json();
if (data && data.routes && data.routes.length > 0) {
const route = data.routes[0];
const coordinates = decodePolyline(route.geometry);
// Add route to map
if (map.getSource("route")) {
map.getSource("route").setData({
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: coordinates,
},
});
} else {
map.addSource("route", {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: coordinates,
},
},
});
map.addLayer({
id: "route",
type: "line",
source: "route",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": "#3b82f6",
"line-width": 5,
},
});
}
return {
distance: route.distance,
duration: route.duration,
};
}
return null;
}
// Polyline decoder function
function decodePolyline(encoded) {
const points = [];
let index = 0,
lat = 0,
lng = 0;
while (index < encoded.length) {
let b,
shift = 0,
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlat = result & 1 ? ~(result >> 1) : result >> 1;
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charCodeAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
const dlng = result & 1 ? ~(result >> 1) : result >> 1;
lng += dlng;
points.push([lng / 1e5, lat / 1e5]);
}
return points;
}
// Usage
const origin = [90.4125, 23.8103];
const destination = [90.3763, 23.7465];
getRoute(origin, destination);
12. Drawing on Map (Polylines, Polygons, Circles)
Polylines
Before:
const path = new google.maps.Polyline({
path: [
{ lat: 23.8103, lng: 90.4125 },
{ lat: 23.7465, lng: 90.3763 },
{ lat: 23.7806, lng: 90.4193 },
],
geodesic: true,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 3,
});
path.setMap(map);
After:
map.on("load", () => {
map.addSource("polyline", {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[90.4125, 23.8103],
[90.3763, 23.7465],
[90.4193, 23.7806],
],
},
},
});
map.addLayer({
id: "polyline",
type: "line",
source: "polyline",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": "#FF0000",
"line-width": 3,
"line-opacity": 1,
},
});
});
Polygons
Before:
const polygon = new google.maps.Polygon({
paths: [
{ lat: 23.82, lng: 90.41 },
{ lat: 23.81, lng: 90.42 },
{ lat: 23.8, lng: 90.41 },
{ lat: 23.81, lng: 90.4 },
],
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
});
polygon.setMap(map);
After:
map.on("load", () => {
map.addSource("polygon", {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
[
[90.41, 23.82],
[90.42, 23.81],
[90.41, 23.8],
[90.4, 23.81],
[90.41, 23.82], // Close the polygon
],
],
},
},
});
// Fill layer
map.addLayer({
id: "polygon-fill",
type: "fill",
source: "polygon",
paint: {
"fill-color": "#FF0000",
"fill-opacity": 0.35,
},
});
// Outline layer
map.addLayer({
id: "polygon-outline",
type: "line",
source: "polygon",
paint: {
"line-color": "#FF0000",
"line-width": 2,
"line-opacity": 0.8,
},
});
});
Circles
Before:
const circle = new google.maps.Circle({
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
map: map,
center: { lat: 23.8103, lng: 90.4125 },
radius: 1000, // meters
});
After:
// Helper function to create circle coordinates
function createCircle(center, radiusKm, points = 64) {
const coords = [];
const distanceX = radiusKm / (111.32 * Math.cos((center[1] * Math.PI) / 180));
const distanceY = radiusKm / 110.574;
for (let i = 0; i < points; i++) {
const theta = (i / points) * (2 * Math.PI);
const x = distanceX * Math.cos(theta);
const y = distanceY * Math.sin(theta);
coords.push([center[0] + x, center[1] + y]);
}
coords.push(coords[0]); // Close the circle
return coords;
}
map.on("load", () => {
const center = [90.4125, 23.8103];
const radiusKm = 1; // 1000 meters = 1 km
map.addSource("circle", {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [createCircle(center, radiusKm)],
},
},
});
map.addLayer({
id: "circle-fill",
type: "fill",
source: "circle",
paint: {
"fill-color": "#FF0000",
"fill-opacity": 0.35,
},
});
map.addLayer({
id: "circle-outline",
type: "line",
source: "circle",
paint: {
"line-color": "#FF0000",
"line-width": 2,
},
});
});
13. Geolocation
Before:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
map.setCenter(pos);
new google.maps.Marker({ position: pos, map: map });
},
() => {
console.error("Geolocation failed");
}
);
}
After:
// Option 1: Built-in control
map.addControl(
new bkoigl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
},
trackUserLocation: true,
showUserHeading: true,
}),
"top-right"
);
// Option 2: Manual implementation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
map.flyTo({
center: [longitude, latitude],
zoom: 15,
});
new bkoigl.Marker().setLngLat([longitude, latitude]).addTo(map);
},
(error) => {
console.error("Geolocation failed:", error);
}
);
}
14. Bounds and Viewport
Before:
const bounds = new google.maps.LatLngBounds();
markers.forEach((marker) => {
bounds.extend(marker.getPosition());
});
map.fitBounds(bounds);
// Get current bounds
const currentBounds = map.getBounds();
const ne = currentBounds.getNorthEast();
const sw = currentBounds.getSouthWest();
After:
const bounds = new bkoigl.LngLatBounds();
markers.forEach((marker) => {
bounds.extend(marker.getLngLat());
});
map.fitBounds(bounds, { padding: 50 });
// Get current bounds
const currentBounds = map.getBounds();
const ne = currentBounds.getNorthEast();
const sw = currentBounds.getSouthWest();
15. Map Methods Comparison
| Previous Method | Barikoi Method |
|---|---|
| map.setCenter(latLng) | map.setCenter([lng, lat]) |
| map.getCenter() | map.getCenter() |
| map.setZoom(zoom) | map.setZoom(zoom) |
| map.getZoom() | map.getZoom() |
| map.panTo(latLng) | map.panTo([lng, lat]) |
| map.fitBounds(bounds) | map.fitBounds(bounds) |
| map.getBounds() | map.getBounds() |
| map.setOptions(opts) | Individual setters |
| map.setMapTypeId(type) | Use style parameter in initialization |
Complete Example: Full Migration
Before (Full HTML):
<!DOCTYPE html>
<html>
<head>
<title>Map Application</title>
<style>
#map {
height: 100vh;
width: 100%;
}
body {
margin: 0;
padding: 0;
}
.search-box {
position: absolute;
top: 10px;
left: 10px;
z-index: 5;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#search-input {
width: 250px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="search-box">
<input id="search-input" type="text" placeholder="Search location..." />
</div>
<div id="map"></div>
<script
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap"
async
defer
></script>
<script>
let map;
let marker;
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 23.8103, lng: 90.4125 },
zoom: 12,
});
const input = document.getElementById("search-input");
const autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo("bounds", map);
autocomplete.addListener("place_changed", () => {
const place = autocomplete.getPlace();
if (!place.geometry) return;
if (marker) marker.setMap(null);
marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
});
const infoWindow = new google.maps.InfoWindow({
content: `<h3>${place.name}</h3><p>${place.formatted_address}</p>`,
});
marker.addListener("click", () => {
infoWindow.open(map, marker);
});
map.setCenter(place.geometry.location);
map.setZoom(16);
});
map.addListener("click", (e) => {
const geocoder = new google.maps.Geocoder();
geocoder.geocode({ location: e.latLng }, (results, status) => {
if (status === "OK" && results[0]) {
if (marker) marker.setMap(null);
marker = new google.maps.Marker({
position: e.latLng,
map: map,
});
const infoWindow = new google.maps.InfoWindow({
content: results[0].formatted_address,
});
infoWindow.open(map, marker);
}
});
});
}
</script>
</body>
</html>
After (Full HTML):
<!DOCTYPE html>
<html>
<head>
<title>Map Application</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<link
rel="stylesheet"
href="https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css"
/>
<script src="https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js"></script>
<style>
#map {
height: 100vh;
width: 100%;
}
body {
margin: 0;
padding: 0;
}
.search-box {
position: absolute;
top: 10px;
left: 10px;
z-index: 5;
background: white;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
width: 300px;
}
#search-input {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
#search-results {
max-height: 200px;
overflow-y: auto;
margin-top: 5px;
}
.search-item {
padding: 8px;
cursor: pointer;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.search-item:hover {
background-color: #f5f5f5;
}
</style>
</head>
<body>
<div class="search-box">
<input id="search-input" type="text" placeholder="Search location..." />
<div id="search-results"></div>
</div>
<div id="map"></div>
<script>
const BARIKOI_API_KEY = "YOUR_BARIKOI_API_KEY";
// Barikoi map style URL with API key
const BARIKOI_STYLE_URL = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${BARIKOI_API_KEY}`;
const map = new bkoigl.Map({
container: "map",
style: BARIKOI_STYLE_URL,
center: [90.4125, 23.8103],
zoom: 12,
});
map.addControl(new bkoigl.NavigationControl(), "top-right");
map.addControl(new bkoigl.FullscreenControl(), "top-right");
let marker = null;
let popup = null;
const input = document.getElementById("search-input");
const resultsContainer = document.getElementById("search-results");
let debounceTimer;
input.addEventListener("input", (e) => {
clearTimeout(debounceTimer);
const query = e.target.value.trim();
if (query.length < 3) {
resultsContainer.innerHTML = "";
return;
}
debounceTimer = setTimeout(async () => {
try {
const response = await fetch(
`https://barikoi.xyz/v1/api/search/autocomplete/${BARIKOI_API_KEY}/place?q=${encodeURIComponent(
query
)}`
);
const data = await response.json();
resultsContainer.innerHTML = "";
if (data.places && data.places.length > 0) {
data.places.forEach((place) => {
const item = document.createElement("div");
item.className = "search-item";
item.textContent = place.address;
item.addEventListener("click", () => {
selectPlace(place);
});
resultsContainer.appendChild(item);
});
} else {
resultsContainer.innerHTML =
'<div class="search-item">No results found</div>';
}
} catch (error) {
console.error("Search error:", error);
}
}, 300);
});
function selectPlace(place) {
input.value = place.address;
resultsContainer.innerHTML = "";
if (marker) marker.remove();
if (popup) popup.remove();
marker = new bkoigl.Marker()
.setLngLat([place.longitude, place.latitude])
.addTo(map);
popup = new bkoigl.Popup({ offset: 25 })
.setLngLat([place.longitude, place.latitude])
.setHTML(
`
<h3>${place.address}</h3>
<p>${place.area || ""}, ${place.city || ""}</p>
<p>Postal Code: ${place.postCode || "N/A"}</p>
`
)
.addTo(map);
marker.setPopup(popup);
map.flyTo({
center: [place.longitude, place.latitude],
zoom: 16,
});
}
map.on("click", async (e) => {
const { lng, lat } = e.lngLat;
try {
const response = await fetch(
`https://barikoi.xyz/v2/api/search/reverse/geocode?api_key=${BARIKOI_API_KEY}&longitude=${lng}&latitude=${lat}&district=true&post_code=true&address=true&area=true`
);
const data = await response.json();
if (marker) marker.remove();
if (popup) popup.remove();
marker = new bkoigl.Marker().setLngLat([lng, lat]).addTo(map);
if (data && data.place) {
popup = new bkoigl.Popup({ offset: 25 })
.setLngLat([lng, lat])
.setHTML(
`
<h3>Location Details</h3>
<p><strong>Address:</strong> ${data.place.address || "N/A"}</p>
<p><strong>Area:</strong> ${data.place.area || "N/A"}</p>
<p><strong>City:</strong> ${data.place.city || "N/A"}</p>
`
)
.addTo(map);
marker.setPopup(popup);
}
} catch (error) {
console.error("Reverse geocode error:", error);
}
});
</script>
</body>
</html>
React / Next.js Migration
Before (React Component):
import { useEffect, useRef } from "react";
import { Loader } from "@googlemaps/js-api-loader";
export default function MapComponent() {
const mapRef = useRef(null);
useEffect(() => {
const loader = new Loader({
apiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
libraries: ["places"],
});
loader.load().then(() => {
const map = new google.maps.Map(mapRef.current, {
center: { lat: 23.8103, lng: 90.4125 },
zoom: 12,
});
new google.maps.Marker({
position: { lat: 23.8103, lng: 90.4125 },
map: map,
});
});
}, []);
return <div ref={mapRef} style={{ width: "100%", height: "500px" }} />;
}
After (React Component):
"use client";
import { useEffect, useRef, useState } from "react";
export default function MapComponent() {
const mapContainerRef = useRef(null);
const mapRef = useRef(null);
const [mapLoaded, setMapLoaded] = useState(false);
useEffect(() => {
const loadBkoiGL = async () => {
if (typeof window !== "undefined" && !window.bkoigl) {
await Promise.all([
new Promise((resolve) => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href =
"https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css";
link.onload = resolve;
document.head.appendChild(link);
}),
new Promise((resolve) => {
const script = document.createElement("script");
script.src =
"https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js";
script.onload = resolve;
document.head.appendChild(script);
}),
]);
}
initializeMap();
};
const initializeMap = () => {
if (!mapContainerRef.current || mapRef.current) return;
const apiKey = process.env.NEXT_PUBLIC_BARIKOI_API_KEY;
const styleUrl = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${apiKey}`;
mapRef.current = new window.bkoigl.Map({
container: mapContainerRef.current,
style: styleUrl,
center: [90.4125, 23.8103],
zoom: 12,
});
mapRef.current.on("load", () => {
setMapLoaded(true);
new window.bkoigl.Marker()
.setLngLat([90.4125, 23.8103])
.addTo(mapRef.current);
});
mapRef.current.addControl(
new window.bkoigl.NavigationControl(),
"top-right"
);
};
loadBkoiGL();
return () => {
if (mapRef.current) {
mapRef.current.remove();
mapRef.current = null;
}
};
}, []);
return (
<div ref={mapContainerRef} style={{ width: "100%", height: "500px" }} />
);
}
React Hook for Barikoi Map:
// hooks/useBarikoiMap.js
"use client";
import { useEffect, useRef, useState } from "react";
export function useBarikoiMap(containerRef, options = {}) {
const mapRef = useRef(null);
const [isLoaded, setIsLoaded] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
const loadSDK = async () => {
try {
if (typeof window === "undefined") return;
if (!window.bkoigl) {
await Promise.all([
loadStylesheet(
"https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css"
),
loadScript("https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js"),
]);
}
if (!isMounted || !containerRef.current) return;
const apiKey =
options.apiKey || process.env.NEXT_PUBLIC_BARIKOI_API_KEY;
const styleUrl = `https://map.barikoi.com/styles/osm-liberty/style.json?key=${apiKey}`;
mapRef.current = new window.bkoigl.Map({
container: containerRef.current,
style: styleUrl,
center: options.center || [90.4125, 23.8103],
zoom: options.zoom || 12,
...options,
});
mapRef.current.on("load", () => {
if (isMounted) setIsLoaded(true);
});
if (options.showControls !== false) {
mapRef.current.addControl(
new window.bkoigl.NavigationControl(),
"top-right"
);
}
} catch (err) {
if (isMounted) setError(err);
}
};
loadSDK();
return () => {
isMounted = false;
if (mapRef.current) {
mapRef.current.remove();
mapRef.current = null;
}
};
}, []);
return { map: mapRef, isLoaded, error };
}
function loadStylesheet(href) {
return new Promise((resolve, reject) => {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
}
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
Usage with Hook:
"use client";
import { useRef } from "react";
import { useBarikoiMap } from "@/hooks/useBarikoiMap";
export default function MapPage() {
const containerRef = useRef(null);
const { map, isLoaded, error } = useBarikoiMap(containerRef, {
center: [90.4125, 23.8103],
zoom: 13,
});
useEffect(() => {
if (isLoaded && map.current) {
new window.bkoigl.Marker()
.setLngLat([90.4125, 23.8103])
.addTo(map.current);
}
}, [isLoaded]);
if (error) return <div>Error loading map</div>;
return (
<div>
{!isLoaded && <div>Loading map...</div>}
<div ref={containerRef} style={{ width: "100%", height: "500px" }} />
</div>
);
}
API Migration Comparison Chart
| Functionality | Previous API | Barikoi API |
|---|---|---|
| Map Display | Maps JavaScript API | bkoigl.Map |
| Markers | google.maps.Marker | bkoigl.Marker |
| Info Windows | google.maps.InfoWindow | bkoigl.Popup |
| Geocoding | Geocoding API | barikoi.xyz/v1/api/search/autocomplete |
| Reverse Geocoding | Geocoding API | barikoi.xyz/v2/api/search/reverse/geocode |
| Places Autocomplete | Places API | barikoi.xyz/v1/api/search/autocomplete |
| Place Details | Places API | barikoi.xyz/v1/api/place/details |
| Directions | Directions API | barikoi.xyz/v2/api/route/detail |
| Distance Matrix | Distance Matrix API | barikoi.xyz/v2/api/route/optimize |
| Nearby Search | Places API | barikoi.xyz/v1/api/search/nearby |
| Administrative Boundaries | Data Layers | Districts, Subdistricts, Ward APIs |
Barikoi API Services Reference
For detailed API documentation, parameters, and examples, visit the official Barikoi API docs:
Location Services
| API | Description |
|---|---|
| Reverse Geocode API | Convert coordinates to human-readable addresses |
| Autocomplete API | Real-time address suggestions while typing |
| Rupantor Geocoder API | Detailed address parsing and normalization |
| Place Details API | Get detailed information about a specific place |
| Nearby API | Find nearby places with filtering options |
Routing Services
| API | Description |
|---|---|
| Route API | Get detailed routing between points |
| Route Optimization API | Optimize routes for multiple stops |
| Snap to Road API | Snap GPS coordinates to the nearest road |
| Route Match API | Match GPS traces to road network |
Administrative Services
| API | Description |
|---|---|
| District API | Get district information |
| Thana API | Get thana/upazila information |
| Ward API | Get ward and zone information |
| Union API | Get union council information |
| Area API | Get area information within cities |
Geospatial Services
| API | Description |
|---|---|
| Ward Geometry API | Get geometry data for wards |
| Point in Polygon API | Check if a point is within a polygon |
| Geofencing API | Create and manage geofences |
Best Practices
API Key Security
- Use environment variables for API keys
- Never expose keys in client-side code in production
- Consider using a backend proxy for API calls
Error Handling
- Always implement try-catch for API calls
- Provide fallback UI for failed map loads
- Handle network errors gracefully
Performance
- Use debouncing for autocomplete (300-500ms)
- Lazy load the map SDK when needed
- Cache frequently accessed data
Coordinate Format
- Remember: Barikoi uses
[longitude, latitude] - Previous implementations used
{lat, lng}objects - Create utility functions for conversion if needed
- Remember: Barikoi uses
// Utility functions
const toBarikoi = ({ lat, lng }) => [lng, lat];
const fromBarikoi = ([lng, lat]) => ({ lat, lng });
- Cleanup
- Always remove map instance on component unmount
- Remove markers and popups when replacing them
- Cancel pending API requests on cleanup
Resources
- Barikoi Documentation: https://docs.barikoi.com/
- Barikoi Developer Portal: https://developer.barikoi.com/
- Barikoi GL JS Examples: https://docs.barikoi.com/docs/maps-api