บทความนี้จะพูดถึงการแนะนำวิธีการพัฒนาแอปพลิเคชันที่มีแผนที่ออนไลน์ (Longdo Map) ผ่าน framework ยอดฮิตอีกตัวอย่าง React Native ซึ่งในก่อนหน้านี้ เราได้มีบทความวิธีการสอนใช้ การใช้แผนที่ Longdo Map ใน Flutter Application ไปแล้ว วันนี้จึงเป็นตาของเฟรมเวิร์คตัวนี้กันบ้าง
หัวข้อต่าง ๆ
- Installation
- Getting Started
- Initial Map
- UI Map
- Marker
- Geometries (Polyline, Polygon, Circle Etc.)
- Routing
- Search
- Documentation
Installation
ติดตั้ง React Native CLI Quickstart ตามคำแนะนำให้เสร็จสิ้น หลังจากนั้นจึงติดตั้ง Longdo Map React Native ด้วยวิธีการต่อไปนี้ (Longdo Map React Native’s Github)
Setting Up (Expo)
เริ่มจากการสร้างโปรเจคและติดตั้ง dependency ต่างๆ
npm install -g expo-cli
npx create-expo-app <PROJECT_NAME> --template blank@47
cd <PROJECT_NAME>
npm install [email protected]
npm install longdo-map-react-native
PROJECT_NAME
คือชื่อโปรเจคที่จะสร้าง
หลังจากนั้นให้ไปที่ไฟล์ babel.config.js เพื่อแก้ไขโค้ดส่วนที่อยู่ใน presets
ดังนี้
presets: [
'babel-preset-expo',
['@babel/preset-env', { "targets": "iOS >= 11, Android >= 56" }],
],
หลังจากนั้นไปที่ไฟล์ app.json ไปที่ ios ใส่ bundleIdentifier, android ใส่ package
"ios": {
"bundleIdentifier": "BUNDLE_ID",
...
"android": {
"package": "PACKAGE_NAME",
BUNDLE_ID
และPACKAGE_NAME
คือเลข bundle และชื่อโปรเจคที่จะสร้าง
Setting Up (React Native CLI)
เริ่มจากการสร้างโปรเจคและติดตั้ง dependency ต่าง ๆ
npm install [email protected] longdo-map-react-native
npm install -D @babel/preset-env
หลังจากนั้นให้ไปที่ไฟล์ babel.config.js เพื่อแก้ไขโค้ดส่วนที่อยู่ใน presets
ดังนี้
presets: [
'module:metro-react-native-babel-preset',
['@babel/preset-env', { "targets": "iOS >= 11, Android >= 56" }],
],
Getting Started
- เพิ่ม Import Longdo ไปยังไฟล์
App.js
import Longdo from 'longdo-map-react-native';
2. ใส่ Key API
Longdo.apiKey = '[Your-Key-API]';
- [Your-Key-API]: สามารถสมัครคีย์ฟรี ! ได้ที่เว็บไซต์ https://map.longdo.com/console
สามารถดูตัวอย่างแบบสมบูรณ์ได้ที่ example/App.js
Initial Map
การสร้างแผนที่พื้นฐาน แบ่งเป็น 2 ส่วน
- ส่วนหลัก
import { SafeAreaView, StyleSheet, Text, View } from "react-native";
import Longdo from "longdo-map-react-native";
let map;
export default function App() {
Longdo.apiKey = "[Your-Key-API]";
return (
<SafeAreaView style={styles.container}>
<Longdo.MapView
ref={(r) => (map = r)}
layer={Longdo.static("Layers", "GRAY")}
zoom={15}
zoomRange={{ min: 4, max: 18 }}
location={{ lon: 100.5382, lat: 13.7649 }}
lastView={false}
// language={'en'}
/>
</SafeAreaView>
);
}
- [Your-Key-API]: สามารถสมัครคีย์ฟรี ! ได้ที่เว็บไซต์ https://map.longdo.com/console
layer
,zoom
,location
,zoomRange
คือการตั้งค่าพื้นฐานของแผนที่ (ดูเพิ่มเติม)
2. ส่วนปรับแต่งการแสดงผล (Style)
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "stretch",
justifyContent: "center",
},
});
ภาพผลลัพธ์
ใช้คำสั่งต่าง ๆ หลังจาก Map ถูกสร้างเสร็จสิ้น
1. สร้างฟังก์ชันเมื่อแผนที่พร้อม
function mapOnReady() {
let location = {lon: 100.5382, lat: 13.7649}
let newMarker = Longdo.object('Marker', location,
{
title: 'Marker',
detail: 'Marker'
}
map.call('Overlays.add', newMarker);
}
2. ผูก Event การทำงานเมื่อแผนที่พร้อม (onReady)
<Longdo.MapView
ref={r => (map = r)}
layer={Longdo.static('Layers', 'GRAY')}
zoom={15}
zoomRange={{min: 5, max: 18}}
location={{lon: 100.5382, lat: 13.7649}}
lastView={false}
// language={'en'}
onReady={mapOnReady}
/>
- onReady คือ ฟังก์ชันเมื่อแผนที่พร้อม ดูเพิ่มเติมหัวข้อ `Longdo.MapView` Component
หมายเหตุ: จะถูกแนะนำเพิ่มเติมในหัวข้อ Map Event และ Overlay Event ต่อไป
Marker
การสร้างหมุดพิกัด (marker) แบบพื้นฐาน
async function addMarker() {
let location = await map.call('location');
let newMarker = Longdo.object('Marker', location, { detail: 'Marker' });
map.call('Overlays.add', newMarker);
}
แบบใส่รูปเอง
async function addMarker() {
let location = await map.call('location');
let newMarker = Longdo.object('Marker', location, { title: 'Marker', detail: 'Marker', icon: { url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAl
wSFlzAAAA3QAAAN0BcFOiBwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAVISURBVFiF7ZdbjFVnF
cd/a+9vn33OnMOZM/cZhtJCKnUAMwEb52IzlUhATUtJlMZGiMYmhdC0tYZofDBR05TERNLEkPbFYJoYcZDoYONDi71MAwz
SArZDbbgOEGbOzJy5nss++/r5MB0Clukwtgk+9P+8Lr9vr/2ttT7RWnMnZdzR7J8D/D8AqPkMRr4u20KXX2NyNGxgaypgR
ah5GIOvGJrFGi6hOVBtcZBuHS4UQOa6Bdn1slK7/CUsswLATECsCkdMEnPE6tcGz9b8WR/+VAAD6yRuR+yPHDZpjRgKrCo
w47cZEA6J8HTmoL68YIDsOvlp6PJL7WOLASoNVmom6gKVM4RvZw7q3tsCGHpQugjZH7o0AagkWJUg5oIT36ixmKIl1a1HP
8nIeK/TOBk6vBW6NBkxKFfBRSWcmhYuFoQgWnjmY0E9B/zlNSWf5+azlav3owHyAq+HBvkAIuBSWRFqaLIj1tWGtGY05jy
lmAhNXnJXMl59L77v8d3pN92OymJDVbeemstHAXwgad6nktXGKOfE452S4sh0DJhpFGeKAV2TPl11EctTH781vhYOTWXon
qzGicokC5epb2zib95ddlvw4VZg75wAJeBluYdziXr+4Taym9PY8YALZUXWM4iAMyXFxbJJf9FnY53PujqN+qiFHSum2Dd
eS9a3rgctFvIMXCgQi8XIWurner18UHtYv3ErAGPMlJ6c2Pz4qZ10bfkefzDu4Zt2xPN1DhsyLovMmRM7kfD2dIy9V+P8f
WimFi/m6tk93HRT8lndbZX5Rc0FGmJBQznP69mvyZ9uCdDRF21OR05xJDdOw+Jm/mXVAXDIr2NThbCj1uH+lI/1Uf2HPJM
DIzYXCkJvYdHHAi4yQnbUjvDCkiusijsYMYhVQlDk0cEuOTfeLumbAAD6o+RP/trTQ27wGtnAJI/Fe1GSg36KKkOxLe2xp
dbhC4kAgHOO4siYwZpE6XogAb6RnuKluy7zrfTUTUNGpUBVQORwb1kYHNooX77uN9uIVq3teFHFrB3JsKz38G70O7fBTFB
gsRSpE7jPjDgdGgx4Bn35GEvtkC13m/xmrJmWuMP2mlGW2+6tvvKMNJSHIfJBLFxbsay2Vw/d1AlbW1uTYZi0+/uPjh/vl
F8NuPbPhgNUCR8TWGVq8houRcKob9BeFRK3k3w1U5g78Q2KfCgOQ66ykWXf38WpPbtWzTmMZnW8U3YXPNl1PhA1oaFa4Iu
m5kQg+MBiW/OArUmnwbDnhzg7JtQ/9BRLNv2AwcfXvjsvwKz6OmTPhCdPnw/F3GRFOBqOBAZnJUXa8Hkk5lCjwJoPRMNV1
YKaniSXz+rbBpjV0XbZm47YntGYA5LkSWMtipANXj+b7TzNgcaMz8wSFOR0NfXmOAChA94k6ADOWAbve7GJBW9EnX36ydX
/1OqaKa+epJKW+1awY/sTvF3RyuGSyTUleGU4NSiMrd7K8udeIfKgPAJubib5cdPiheklKEvt/59Xsra+aGNPWP9sRUWCk
YLLmrZ2Ro00bznCqBICINW8jNxr3TN/vwvTJvxRp9hXaOSxyuy+Hx3L71xwCW6UiKg1HQ+6z+x8wjhx8jQTvQf4kn8FQ4S
uRETG18QNuKIMXnEqOeFlWGqWou9khh9/uFf/Hj5hJbtdrVzbvk1Z1ssiQsKZ8B8xzmqJghhA3IR/BxlOhrW0mJN6fWq8r
9EOfrjhDf3h9UN8Fi+jlWvaNoN0ekH02/P9J671PGA8P+Xpx8qRVJdQXrMdHloahM+09enp//b9TAA+je74u+BzgDsO8B/
ytjz4VPeucgAAAABJRU5ErkJggg==', offset: { x: 16, y: 16 }} });
map.call('Overlays.add', newMarker);
}
see more: Marker option Documentation
หมายเหตุ: API รับรูปภาพเฉพาะ format data URL (base 64 และ url รูปภาพ)
Geometries – รูปทรงต่าง ๆ
Polygon
function addPolygon() {
let geomLocation = [
{ lon: 99, lat: 14 },
{ lon: 100, lat: 13 },
{ lon: 102, lat: 13 },
{ lon: 103, lat: 14 }
];
let newGeom = Longdo.object('Polygon', geomLocation, { detail: 'Polygon' });
map.call('Overlays.add', newGeom);
}
ดูเพิ่มเติม: JavaScript Map API, React Native docs – Object
Routing
การค้นหาเส้นทาง ด้วยการส่งพิกัดจุดต้นและปลายทาง
function routing() {
let starterPoint = Longdo.object('Marker', {lon: 100.5, lat: 13.7}, { detail: 'Home' });
let destinationPoint = Longdo.object('Marker', {lon: 100.5382, lat: 13.7649}, { detail: 'Destination' });
map.call('Route.add', starterPoint);
map.call('Route.add', destinationPoint);
map.call('Route.search');
}
Change the color path
map.call('Route.line', 'road', { lineColor: '#009910', lineWidth: '1', borderColor: '#000000', borderWidth : '1' });
- เรียกคำสั่งข้างต้น ก่อนไปคำสั่ง Route.search
ดูเพิ่มเติม: React Native call function, JavaScript routing option
Search
การทำช่องค้นหา โดยเรียกผ่าน Web Service ให้ผลลัพธ์ตามตัวอย่างภาพนี้
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
let map;
let keyAPI = 'YOUR-KEY-APII'; //Registered the Key from https://map.longdo.com/console
function HomeScreen({navigation}) {
Longdo.apiKey = keyAPI;
return (
<SafeAreaView style={styles.container}>
<TextInput
style={styles.input}
placeholder="ใส่คำค้นหา"
onFocus={() => navigation.navigate('Search')}
/>
<Longdo.MapView
ref={r => (map = r)}
layer={Longdo.static('Layers', 'GRAY')}
zoom={15}
zoomRange={{min: 5, max: 18}}
location={{lon: 100.5382, lat: 13.7649}}
onSearch={onSearch}
lastView={false}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
},
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
backgroundColor: '#fff',
zIndex: 10,
},
buttonBack: {
marginVertical: 12,
marginHorizontal: 10,
height: 40,
},
inputSearch: {
flex: 6,
height: 40,
marginRight: 12,
marginTop: 12,
borderWidth: 1,
padding: 10,
backgroundColor: '#fff',
zIndex: 10,
},
textSuggest: {
paddingHorizontal: 20,
paddingVertical: 10,
marginHorizontal: 12,
backgroundColor: 'white',
},
})
ฟังก์ชัน SeachScreen มีการเรียกใช้ทั้ง suggest web service และ search web service
function SearchScreen({navigation}) {
// *****************************************************************
const [search, setSearch] = useState('');
const [filteredDataSource, setFilteredDataSource] = useState([]);
const searchFilterFunction = text => {
if (text.length >= 3) {
const urlSuggest =
'https://search.longdo.com/mapsearch/json/suggest?limit=10&key=' +
keyAPI +
'&keyword=' +
text;
fetch(urlSuggest)
.then(response => response.json())
.then(responseJson => {
setFilteredDataSource(responseJson.data);
})
.catch(error => {
console.error(error);
});
setSearch(text);
} else {
setFilteredDataSource([]);
setSearch(text);
}
};
const ItemSeparatorView = () => {
return (
// Flat List Item Separator
<View
style={{
height: 1,
backgroundColor: '#C8C8C8',
marginHorizontal: 12,
}}
/>
);
};
const getItem = item => {
const urlSearch =
'https://search.longdo.com/mapsearch/json/search?limit=20&key=' +
keyAPI +
'&keyword=' +
item;
fetch(urlSearch)
.then(response => response.json())
.then(responseJson => {
map.call('Overlays.clear');
responseJson.data.forEach(item => {
let newMarker = Longdo.object(
'Marker',
{lat: item.lat, lon: item.lon},
{
title: item.name,
detail: item.address,
},
);
map.call('Overlays.add', newMarker);
});
let location = {
lon: responseJson.data[0].lon,
lat: responseJson.data[0].lat,
};
map.call('location', location);
navigation.navigate('Home', {
responseJson: responseJson.data,
});
})
.catch(error => {
console.error(error);
});
};
const Item = ({title}) => {
return (
<View>
<Text style={styles.textSuggest} onPress={() => getItem(title)}>
{title}
</Text>
</View>
);
};
const DATA = [
{
data: filteredDataSource.map(item => item.w),
},
];
// ***************************************************************
return (
<View>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity style={styles.buttonBack}>
<Button title="Back" onPress={() => navigation.navigate('Home')} />
</TouchableOpacity>
<TextInput
style={styles.inputSearch}
onChangeText={text => searchFilterFunction(text)}
autoFocus
value={search}
placeholder="ใส่คำค้นหา"
/>
</View>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
ItemSeparatorComponent={ItemSeparatorView}
renderItem={({item}) => <Item title={item} />}
/>
</View>
);
}
ส่วน view แสดงผล (มีการเรียกฟังก์ชัน SearchScreen และ HomeScreen ตามข้างต้น)
const Stack = createNativeStackNavigator();
const App: () => Node = () => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Search" component={SearchScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
Documentation
- Reference
- JavaScript Documentation
- [Geolocation] (https://www.npmjs.com/package/react-native-geolocation-service)
- [Foreground Service] (https://github.com/voximplant/react-native-foreground-service)
จบไปแล้วครับ ตัวอย่างการเขียน Longdo Map ผ่าน React Native มีวิธีติดตาม Longdo Map ได้ง่ายๆ หลายช่องทาง ดังนี้
- ศึกษาการใช้ Longdo Map เพิ่มเติมได้ที่ https://map.longdo.com/docs/
- ดูเคล็ดลับและเทคนิคอื่นๆ เพิ่มเติมได้ที่ https://map.longdo.com/blog
- เรียนเชิญนักพัฒนาเว็บทุกท่านเข้าร่วมกลุ่ม Longdo Map API Community กันได้ที่นี่เลยครับ 🙂 https://www.facebook.com/groups/708165893234850
พบกันในบทความถัดไปครับ