Skip to main content

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:

  1. Replace script/API loading mechanism
  2. Update map initialization code
  3. Replace API key references
  4. Update coordinate format (LatLng objects -> [lng, lat] arrays)
  5. Migrate markers, popups, and overlays
  6. Update geocoding and places services
  7. Migrate routing/directions services
  8. 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 style URL with your API key for the map to load.

3. API Keys

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 EventBarikoi Event
clickclick
dblclickdblclick
mousemovemousemove
mouseentermouseenter
mouseleavemouseleave
zoom_changedzoom
bounds_changedmoveend
dragstartdragstart
dragdrag
dragenddragend
idleidle
tilesloadedload
center_changedmove
heading_changedrotate
tilt_changedpitch

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 MethodBarikoi 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

FunctionalityPrevious APIBarikoi API
Map DisplayMaps JavaScript APIbkoigl.Map
Markersgoogle.maps.Markerbkoigl.Marker
Info Windowsgoogle.maps.InfoWindowbkoigl.Popup
GeocodingGeocoding APIbarikoi.xyz/v1/api/search/autocomplete
Reverse GeocodingGeocoding APIbarikoi.xyz/v2/api/search/reverse/geocode
Places AutocompletePlaces APIbarikoi.xyz/v1/api/search/autocomplete
Place DetailsPlaces APIbarikoi.xyz/v1/api/place/details
DirectionsDirections APIbarikoi.xyz/v2/api/route/detail
Distance MatrixDistance Matrix APIbarikoi.xyz/v2/api/route/optimize
Nearby SearchPlaces APIbarikoi.xyz/v1/api/search/nearby
Administrative BoundariesData LayersDistricts, Subdistricts, Ward APIs

Barikoi API Services Reference

For detailed API documentation, parameters, and examples, visit the official Barikoi API docs:

https://docs.barikoi.com/api

Location Services

APIDescription
Reverse Geocode APIConvert coordinates to human-readable addresses
Autocomplete APIReal-time address suggestions while typing
Rupantor Geocoder APIDetailed address parsing and normalization
Place Details APIGet detailed information about a specific place
Nearby APIFind nearby places with filtering options

Routing Services

APIDescription
Route APIGet detailed routing between points
Route Optimization APIOptimize routes for multiple stops
Snap to Road APISnap GPS coordinates to the nearest road
Route Match APIMatch GPS traces to road network

Administrative Services

APIDescription
District APIGet district information
Thana APIGet thana/upazila information
Ward APIGet ward and zone information
Union APIGet union council information
Area APIGet area information within cities

Geospatial Services

APIDescription
Ward Geometry APIGet geometry data for wards
Point in Polygon APICheck if a point is within a polygon
Geofencing APICreate and manage geofences

Best Practices

  1. 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
  2. Error Handling

    • Always implement try-catch for API calls
    • Provide fallback UI for failed map loads
    • Handle network errors gracefully
  3. Performance

    • Use debouncing for autocomplete (300-500ms)
    • Lazy load the map SDK when needed
    • Cache frequently accessed data
  4. Coordinate Format

    • Remember: Barikoi uses [longitude, latitude]
    • Previous implementations used {lat, lng} objects
    • Create utility functions for conversion if needed
// Utility functions
const toBarikoi = ({ lat, lng }) => [lng, lat];
const fromBarikoi = ([lng, lat]) => ({ lat, lng });
  1. Cleanup
    • Always remove map instance on component unmount
    • Remove markers and popups when replacing them
    • Cancel pending API requests on cleanup

Resources