diff --git a/package.json b/package.json
index 9449491..bc44243 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
+ "build-localhost": "PUBLIC_URL=/ react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
diff --git a/src/assets/data/poi.geojson b/src/assets/data/poi.geojson
new file mode 100644
index 0000000..101b654
--- /dev/null
+++ b/src/assets/data/poi.geojson
@@ -0,0 +1 @@
+{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "肉老大頂級肉品涮涮鍋-敦南創始店", "address": "台北市大安區敦化南路二段331巷16號", "description": "以下優惠二擇一:\n內用 9折優惠、外帶 95折優惠\n4人同行送一盤7oz肉盤 (豬or牛)\n打卡送肉、蝦", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.549826, 25.022635]}}, {"id": "1", "type": "Feature", "properties": {"status": "Inactive", "class": "餐廳", "subclass": "general_restaurant", "name": "肉老大頂級肉品涮涮鍋-東區店", "address": "台北市大安區敦化南路一段190巷48號", "description": null, "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.54673, 25.042521]}}, {"id": "2", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "肉老大頂級肉品涮涮鍋-淡水店", "address": "新北市淡水區民權路157號", "description": null, "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.460055, 25.136078]}}, {"id": "3", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "肉老大頂級肉品涮涮鍋-中和店", "address": "新北市中和區中和路380號2樓", "description": null, "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.510757, 25.002113]}}, {"id": "4", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "EZFive", "address": "台北市大安區安和路二段211號", "description": "招待爆米花或洋芋片", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.5502, 25.026074]}}, {"id": "5", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "青沐初食", "address": "台北市大安區敦化南路二段265巷7號", "description": "平日9折優惠(不含套餐),限持員工證本人使用", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.549544, 25.02548]}}, {"id": "6", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "burger", "name": "漢堡王 敦化店", "address": "台北市大安區敦化南路二段164號", "description": "提供套餐薯條升級\n早餐套餐咖啡升級研磨咖啡", "expiration": "2022-10-31"}, "geometry": {"type": "Point", "coordinates": [121.548338, 25.024428]}}, {"id": "7", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "西羅伐", "address": "台北市大安區敦化南路二段146巷1號", "description": "現職員工9折優惠", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.548157, 25.025538]}}, {"id": "8", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "japanese_restaurant", "name": "竹鶴日本料理店", "address": "新竹縣竹北市光明一路175號1樓", "description": "9折優惠(現金消費)\n95折優惠(刷卡消費)", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.014685, 24.830345]}}, {"id": "9", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "彭家涼麵", "address": "台北市大安區嘉興街399號1樓", "description": "全品項9折(特惠組合除外)", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.551145, 25.021528]}}, {"id": "10", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "bistro", "name": "Le Chamber", "address": "台北市大安區敦化南路二段152號之一", "description": "- 用餐2~4人送一份蒜味薯條,4人以上送兩份蒜味薯條 (星期日,二,三,四需滿低消$500/位, 其他為$1000/位)\n- 25人包場75折 (兩小時, 包場費可折抵餐費)", "expiration": "2023-04-13"}, "geometry": {"type": "Point", "coordinates": [121.548167, 25.025189]}}, {"id": "11", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "炊牛王牛肉麵專賣店", "address": "新竹市東區新莊街111號", "description": "每項單品減10元(小菜除外)", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.016717, 24.786749]}}, {"id": "12", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-台北美麗華店", "address": "台北市中山區敬業三路20號5F", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.556712, 25.082926]}}, {"id": "13", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-台北京站店", "address": "台北市大同區承德路一段1號4F", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.516784, 25.04909]}}, {"id": "14", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-信義誠品店", "address": "台北市信義區松高路11號", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.565242, 25.039515]}}, {"id": "15", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-南港CITYLINK店", "address": "台北市南港區忠孝東路七段299號C棟 1樓", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.604792, 25.052364]}}, {"id": "16", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-板橋大遠百店", "address": "新北市板橋區新站路28號9樓", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.466627, 25.013622]}}, {"id": "17", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-新莊晶冠店", "address": "新北市新莊區五工路66號", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.458702, 25.063818]}}, {"id": "18", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-新竹巨城店PARK15", "address": "新竹市東區中央路229號7樓", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.974931, 24.809666]}}, {"id": "19", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-中壢SOGO店", "address": "桃園市中壢區元化路357號8樓", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.223533, 24.962685]}}, {"id": "20", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-台中市政店", "address": "台中市西屯區市政路20號", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.645394, 24.156264]}}, {"id": "21", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-台中勤美店", "address": "台中市西區公益路68號B1", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.663866, 24.151278]}}, {"id": "22", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-台南南紡店", "address": "台南市東區中華東路一段366號5F", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.233334, 22.990772]}}, {"id": "23", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-高雄義大店", "address": "高雄市大樹區學城路一段12號A區5F", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.406614, 22.729832]}}, {"id": "24", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "金色三麥-漢神巨蛋店", "address": "高雄市左營區博愛二路777號4樓", "description": "LINE\n會員消費贈送\n雙倍點數", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.303118, 22.670155]}}, {"id": "25", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "UMAMI 金色三麥 - 微風南山店", "address": "台北市信義區松智路17號7樓", "description": "1. 門市內用消費享 原價 9 折優惠。\n2. LINE 會員消費贈送雙倍點數。\n3. 以上 優惠 二擇 一, 套餐 與其他優 惠皆不併用", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.565774, 25.034434]}}, {"id": "26", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "Petit Doux 微兜 Café-永康店", "address": "台北市大安區信義路二段 198 巷 7-3 號1樓", "description": "1. 門市內用消費單筆滿 500 元 不含套餐 )),即贈主廚私房菜乙份,本優惠 不累贈 。\n2. 與其它優惠皆不併用。", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.530682, 25.032665]}}, {"id": "27", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "Petit Doux 微兜 Café-北車京站店", "address": "台北市大同區承德路一段1號1樓", "description": "1. 門市內用消費單筆滿 500 元 不含套餐 )),即贈主廚私房菜乙份,本優惠 不累贈 。\n2. 與其它優惠皆不併用。", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.516784, 25.04909]}}, {"id": "28", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "Petit Doux 微兜 Café-小碧潭店", "address": "新北市新店區中央路157號5樓", "description": "1. 門市內用消費單筆滿 500 元 不含套餐 )),即贈主廚私房菜乙份,本優惠 不累贈 。\n2. 與其它優惠皆不併用。", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.530551, 24.972512]}}, {"id": "29", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "Petit Doux 微兜 Café-SOGO忠孝店", "address": "台北市忠孝東路四段45號11樓", "description": "1. 門市內用消費單筆滿 500 元 不含套餐 )),即贈主廚私房菜乙份,本優惠 不累贈 。\n2. 與其它優惠皆不併用。", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.544883, 25.041902]}}, {"id": "30", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "Petit Doux 微兜 Café-漢神巨蛋店", "address": "高雄市左營區博愛二路777號4樓", "description": "1. 門市內用消費單筆滿 500 元 不含套餐 )),即贈主廚私房菜乙份,本優惠 不累贈 。\n2. 與其它優惠皆不併用。", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.303118, 22.670155]}}, {"id": "31", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cake", "name": "BAC cake sweets-台北站前凱薩門市", "address": "台北市中正區忠孝西路一段38號 ", "description": "1. 購買 6 吋以上生日蛋糕享 9 折優惠,如需宅配運費另計。\n2. 與其它優惠皆不併用", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.516436, 25.046215]}}, {"id": "32", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cake", "name": "BAC cake sweets-台北忠孝光復門市", "address": "台北市光復南路240巷23號", "description": "1. 購買 6 吋以上生日蛋糕享 9 折優惠,如需宅配運費另計。\n2. 與其它優惠皆不併用", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.556467, 25.040658]}}, {"id": "33", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cake", "name": "BAC cake sweets-台北忠孝Sogo門市", "address": "台北市忠孝東路四段45號B1", "description": "1. 購買 6 吋以上生日蛋糕享 9 折優惠,如需宅配運費另計。\n2. 與其它優惠皆不併用", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.544883, 25.041902]}}, {"id": "34", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cake", "name": "BAC cake sweets-台中勤美門市", "address": "台中市西區公益路68號1樓", "description": "1. 購買 6 吋以上生日蛋糕享 9 折優惠,如需宅配運費另計。\n2. 與其它優惠皆不併用", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [120.663866, 24.151278]}}, {"id": "35", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "咖哩樹-台北京站店", "address": "台北市大同區承德路一段1號B3F (食樂大道)", "description": "憑員工識別證 消費享免費升級套餐", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.516784, 25.04909]}}, {"id": "36", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "咖哩樹-板橋環球店", "address": "新北市板橋區縣民大道二段七號B1F (美食天地)", "description": "憑員工識別證 消費享免費升級套餐", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.463635, 25.01433]}}, {"id": "37", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "咖哩樹-桃園A19店", "address": "桃園市中壢區高鐵南路二段352號3F (運動 ‧ 品食尚)", "description": "憑員工識別證 消費享免費升級套餐", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.202935, 25.002445]}}, {"id": "38", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "咖哩樹-中壢SOGO店", "address": "桃園市中壢區元化路357號B1F (美食廣場)", "description": "憑員工識別證 消費享免費升級套餐", "expiration": "2022-12-31"}, "geometry": {"type": "Point", "coordinates": [121.223533, 24.962685]}}, {"id": "39", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "悠悠河畔", "address": "台北市大安區樂業街50號1樓", "description": "a.單杯飲品95折\nb.十杯飲品以上9折", "expiration": null}, "geometry": {"type": "Point", "coordinates": [121.549751, 25.022852]}}, {"id": "40", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "龜記-大安信義店", "address": "台北市大安區信義路三段192號", "description": "50杯95折,100杯9折\n現場外帶自取滿百折10元,以此類推", "expiration": null}, "geometry": {"type": "Point", "coordinates": [121.543006, 25.03319]}}, {"id": "41", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "山焙-和平臥龍店", "address": "10670台北市大安區和平東路二段363號", "description": "a. 自取或外帶:中杯冷飲享免費升級大杯;熱飲享95折優惠。 \nb. 外送:買10杯送1杯(以最低價飲品做為贈送) \n以上優惠須於訂購時主動出示(自取電話告知)員工識別證;現場及自取購買每張識別證可購買上限為5杯為限。", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.5464319, 25.0248104274316]}}, {"id": "42", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "茶三小", "address": "106台北市大安區和平東路三段123號", "description": "a. 全品項9折優惠\nb. 提前一天預訂外送滿300,88折\nc. 提前一天預訂自取滿300,87折", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.5517288, 25.0246272]}}, {"id": "43", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "bread", "name": "麥將軍烘焙", "address": "106台北市大安區和平東路二段285號", "description": "消費滿百 出示貴公司相關證件 打九折, 優惠內容不包含餐盒、節慶禮盒、特價商品及不與活動併用。", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.5445601, 25.0249521]}}, {"id": "44", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "shop", "name": "台灣好漁", "address": "台北市貴陽街2段1號之4", "description": "85折起", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.506755, 25.039413]}}, {"id": "45", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cake", "name": "無二蛋糕", "address": "台北市大安區安和路二段184巷10號", "description": "1. 當日消費滿600元,送當日小點心一份,送完為止\n2. 預訂蛋糕金額滿2000元,享95折優惠", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.549858, 25.024992]}}, {"id": "46", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "shop", "name": "蜂蜜皇后", "address": "台北市大安區忠孝東路四段221號12樓", "description": "95折", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.552577, 25.041661]}}, {"id": "47", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "魏姐包心粉圓", "address": "新竹市光復路一段360-3號", "description": "9折", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.017563, 24.783541]}}, {"id": "48", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "shop", "name": "follow蜜 (築蜜企業社)", "address": "新竹縣竹北市嘉豐11路2段10號", "description": "飲品每杯 折扣5元\n蜂蜜商品(瓶裝) 9折優惠", "expiration": "自動展延"}, "geometry": null}, {"id": "49", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "一手私藏世界紅茶(新竹光復店)", "address": "新竹市東區光復路一段362-15號", "description": "9折", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.016116, 24.784092]}}, {"id": "50", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "BonTree 好樹早午餐", "address": "台北市基隆路二段285號", "description": "到店用餐出示識別證享有優惠價格", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.549772, 25.021644]}}, {"id": "51", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "日日良選 (科技大樓店)", "address": "台北市大安區和平東路二段311巷3號", "description": "飲品每杯 折扣5元,現場購買及外送皆適用", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.545203, 25.024982]}}, {"id": "52", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "羽上茶飲", "address": "台北市信義區莊敬路302號", "description": "買10杯送一杯\n20杯以上折95折~85折\n(欲外送請透過電話or Line點餐方能享折扣)", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.563111, 25.028365]}}, {"id": "53", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "CAFE!N 延吉店", "address": "台北市大安區忠孝東路四段 50-2 號", "description": "一. 外送優惠:\n1. 單筆訂購咖啡與餐食金額滿 1,000 元享有 9 折企業會員優惠與三公里免運費外送服務。\n2. 單筆訂購咖啡與餐食金額滿 3,000 元享有 8 折企業會員優惠與三公里免運費外送服務。\n3. 企業會員訂單限定飲品與餐食 ,外送距離若超過 500 公尺,訂單請於至少 3 小時前下單。\n二. 咖啡周邊團購:\n1. 濾掛咖啡/咖啡豆,訂滿 10 組享 9 折優惠與三公里免運費外送服務。\n2. 濾掛咖啡/咖啡豆,訂滿 20 組享 8 折優惠與三公里免運費外送服務。\n\n訂購專線:(02)8771-38611 或 Line ID: cafein01", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.544985, 25.041392]}}, {"id": "54", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "general_restaurant", "name": "一生懸雞(光復店)", "address": "新竹市東區光復路499號", "description": "外送雞排65元(其餘原價)\n來店消費全面九折", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.014157, 24.784452]}}, {"id": "55", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "COFFEE LOVER's PLANET 敦北店", "address": "台北市大安區敦化南路1段246號號 B1", "description": "憑趨勢識別證至門市消費\n1. 可享全面9折優惠(包含購買咖啡豆)\n2. 加入門市會員,每次消費可享點數雙倍送", "expiration": null}, "geometry": {"type": "Point", "coordinates": [121.548441, 25.040146]}}, {"id": "56", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "cafe", "name": "COFFEE LOVER's PLANET 新竹店", "address": "新竹市東區中央路239號", "description": "憑趨勢識別證至門市消費\n1. 可享全面9折優惠(包含購買咖啡豆)\n2. 加入門市會員,每次消費可享點數雙倍送", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [120.976204, 24.809614]}}, {"id": "57", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "sports", "name": "24磅咖啡羽球", "address": "台北市中正區寧波東街3-1號", "description": "a.\t單品咖啡豆享9折優惠 \nb.\t飲品享10元優惠 \nc.\t羽球拍、羽球鞋、服飾享95折優惠 \n", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.519735, 25.03223]}}, {"id": "58", "type": "Feature", "properties": {"status": "Active", "class": "餐廳", "subclass": "drink", "name": "Swiido 走糖 萬隆示範店", "address": "台北市文山區羅斯福路五段211巷18號", "description": "1.\t首次外送總金額享85折優惠,免收運費且不限定外送距離。\n(門市活動優惠不能同時使用)\n2.\t第二次外送總金額享85折優惠,免收運費但折扣後之消費金額須達外送距離之規定金額。\n(外送達標金額依外送距離不同而異,門市活動優惠不能同時使用)\n3.\t凡貴公司人員至現場消費即可享有9折優惠。\n(門市活動優惠不能同時使用)\n", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.539306, 25.002281]}}, {"id": "59", "type": "Feature", "properties": {"status": "Inactive", "class": "餐廳", "subclass": "drink", "name": "走糖手搖", "address": "台北市中山區長安東路二段258號", "description": "1.\t首次外送總金額享85折優惠,免收運費且不限定外送距離。\n(門市活動優惠不能同時使用)\n2.\t第二次外送總金額享85折優惠,免收運費但折扣後之消費金額須達外送距離之規定金額。\n(外送達標金額依外送距離不同而異,門市活動優惠不能同時使用)\n3.\t凡貴公司人員至現場消費即可享有9折優惠。\n(門市活動優惠不能同時使用)\n", "expiration": "自動展延"}, "geometry": {"type": "Point", "coordinates": [121.543666, 25.048158]}}]}
\ No newline at end of file
diff --git a/src/assets/icons/beer.svg b/src/assets/icons/beer.svg
new file mode 100644
index 0000000..4b48095
--- /dev/null
+++ b/src/assets/icons/beer.svg
@@ -0,0 +1,74 @@
+
+
+
diff --git a/src/assets/icons/bread.svg b/src/assets/icons/bread.svg
new file mode 100644
index 0000000..d3bc380
--- /dev/null
+++ b/src/assets/icons/bread.svg
@@ -0,0 +1,54 @@
+
+
+
diff --git a/src/assets/icons/burger.svg b/src/assets/icons/burger.svg
new file mode 100644
index 0000000..7495b09
--- /dev/null
+++ b/src/assets/icons/burger.svg
@@ -0,0 +1,82 @@
+
+
+
diff --git a/src/assets/icons/cafe.svg b/src/assets/icons/cafe.svg
new file mode 100644
index 0000000..b1ce646
--- /dev/null
+++ b/src/assets/icons/cafe.svg
@@ -0,0 +1,27 @@
+
+
+
+
diff --git a/src/assets/icons/cake.svg b/src/assets/icons/cake.svg
new file mode 100644
index 0000000..dd52639
--- /dev/null
+++ b/src/assets/icons/cake.svg
@@ -0,0 +1,75 @@
+
+
+
diff --git a/src/assets/icons/drink.svg b/src/assets/icons/drink.svg
new file mode 100644
index 0000000..0ee5144
--- /dev/null
+++ b/src/assets/icons/drink.svg
@@ -0,0 +1,61 @@
+
+
+
diff --git a/src/assets/icons/fruit.svg b/src/assets/icons/fruit.svg
new file mode 100644
index 0000000..988af40
--- /dev/null
+++ b/src/assets/icons/fruit.svg
@@ -0,0 +1,51 @@
+
+
+
diff --git a/src/assets/icons/general_restaurant.svg b/src/assets/icons/general_restaurant.svg
new file mode 100644
index 0000000..90d08fa
--- /dev/null
+++ b/src/assets/icons/general_restaurant.svg
@@ -0,0 +1,45 @@
+
+
+
diff --git a/src/assets/icons/japanese_restaurant.svg b/src/assets/icons/japanese_restaurant.svg
new file mode 100644
index 0000000..9c02488
--- /dev/null
+++ b/src/assets/icons/japanese_restaurant.svg
@@ -0,0 +1,81 @@
+
+
+
diff --git a/src/assets/icons/shop.svg b/src/assets/icons/shop.svg
new file mode 100644
index 0000000..362cbb2
--- /dev/null
+++ b/src/assets/icons/shop.svg
@@ -0,0 +1,75 @@
+
+
+
diff --git a/src/assets/icons/sports.svg b/src/assets/icons/sports.svg
new file mode 100644
index 0000000..699a615
--- /dev/null
+++ b/src/assets/icons/sports.svg
@@ -0,0 +1,64 @@
+
+
+
diff --git a/src/assets/icons/trend_micro.svg b/src/assets/icons/trend_micro.svg
new file mode 100644
index 0000000..26d8d5f
--- /dev/null
+++ b/src/assets/icons/trend_micro.svg
@@ -0,0 +1,30 @@
+
+
+
+
diff --git a/src/assets/icons/wine.svg b/src/assets/icons/wine.svg
new file mode 100644
index 0000000..72f3ef1
--- /dev/null
+++ b/src/assets/icons/wine.svg
@@ -0,0 +1,63 @@
+
+
+
diff --git a/src/components/Map/Layer/CompanyLayer.js b/src/components/Map/Layer/CompanyLayer.js
new file mode 100644
index 0000000..4b0e1c3
--- /dev/null
+++ b/src/components/Map/Layer/CompanyLayer.js
@@ -0,0 +1,61 @@
+import { Fragment } from "react";
+import { Source, Layer } from "react-map-gl";
+
+const CompanySource = () => {
+ const companys = {
+ type: "FeatureCollection",
+ features: [
+ {
+ id: "1",
+ type: "Feature",
+ geometry: {
+ type: "Point",
+ coordinates: [121.54838821352193, 25.02312941733473],
+ },
+ properties: {
+ name: "趨勢科技",
+ "name:en": "Trend Micro Inc.",
+ class: "公司",
+ address: "106台北市大安區敦化南路二段198號",
+ description:
+ "趨勢科技為網路資安全球領導廠商,致力建立一個安全的資訊交換世界。憑藉著數十年的資安專業、全球威脅研究以及持續不斷的創新,我們跨雲端、網路、裝置及端點的網路資安平台隨時守護著全球 50 多萬家企業機構及 2.5 億以上的一般使用者。",
+ },
+ },
+ ],
+ };
+
+ const layerStyle = {
+ id: "company",
+ type: "symbol",
+ layout: {
+ "text-anchor": "top",
+ "text-field": "{name}\n{name:en}",
+ "text-font": ["Noto Sans Regular"],
+ "text-offset": [0, 0.6],
+ "text-padding": 2,
+ "text-size": 14,
+ "icon-image": "trend_micro",
+ },
+ paint: {
+ "text-color": [
+ "case",
+ ["boolean", ["feature-state", "hover"], false],
+ "rgba(3, 117, 214, 1)",
+ "#1544AF",
+ ],
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1,
+ },
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default CompanySource;
diff --git a/src/components/Map/Layer/PoiLayer.js b/src/components/Map/Layer/PoiLayer.js
new file mode 100644
index 0000000..5bbc644
--- /dev/null
+++ b/src/components/Map/Layer/PoiLayer.js
@@ -0,0 +1,42 @@
+import { Fragment } from "react";
+import { useSelector } from "react-redux";
+import { Source, Layer } from "react-map-gl";
+
+const layerStyle = {
+ id: "poi",
+ type: "symbol",
+ layout: {
+ "text-anchor": "top",
+ "text-field": "{name}",
+ "text-font": ["Noto Sans Regular"],
+ "text-offset": [0, 0.6],
+ "text-padding": 2,
+ "text-size": 14,
+ "icon-image": "{subclass}",
+ "text-max-width": 30,
+ },
+ paint: {
+ "text-color": [
+ "case",
+ ["boolean", ["feature-state", "hover"], false],
+ "rgba(3, 117, 214, 1)",
+ "#B45118",
+ ],
+ "text-halo-blur": 0.5,
+ "text-halo-color": "#ffffff",
+ "text-halo-width": 1,
+ },
+};
+
+const PoiLayer = () => {
+ const poiGeojson = useSelector((state) => state.map.poiGeojson);
+ return (
+
+
+
+ );
+};
+
+export default PoiLayer;
diff --git a/src/components/Map/MapView.js b/src/components/Map/MapView.js
index 5ae64fa..43da354 100644
--- a/src/components/Map/MapView.js
+++ b/src/components/Map/MapView.js
@@ -1,10 +1,20 @@
import { useRef, useState, useCallback, Fragment } from "react";
import { useSelector, useDispatch } from "react-redux";
import { mapActions } from "../../store/map-slice";
+import { fetchPoiGeojson } from "../../store/map-actions";
-import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
import Map, { NavigationControl, ScaleControl } from "react-map-gl";
+import icons from "../../utils/icons";
+import PoiLayer from "./Layer/PoiLayer";
+import CompanyLayer from "./Layer/CompanyLayer";
+
+// In order to solve the bug in production: Uncaught ReferenceError: y is not defined
+// import maplibregl from "maplibre-gl";
+// eslint-disable-next-line import/no-webpack-loader-syntax
+import maplibregl from '!maplibre-gl'; // ! is important here
+import maplibreglWorker from 'maplibre-gl/dist/maplibre-gl-csp-worker';
+maplibregl.workerClass = maplibreglWorker;
const MapView = () => {
const dispatch = useDispatch();
@@ -14,6 +24,17 @@ const MapView = () => {
const mapStyle = useSelector((state) => state.map.mapStyle);
const onMapLoad = useCallback(() => {
+ // Add all icons to map
+ for (const key of Object.keys(icons)) {
+ let img = new Image(20, 20);
+ img.onload = () => mapRef.current.addImage(key, img);
+ img.src = icons[key];
+ }
+
+ // Fetch poi geojson from static file
+ dispatch(fetchPoiGeojson());
+
+ // Set cursor
mapRef.current.on("dragstart", () => {
setCursor("move");
});
@@ -21,7 +42,7 @@ const MapView = () => {
mapRef.current.on("dragend", () => {
setCursor("auto");
});
- }, []);
+ }, [dispatch]);
const onMove = useCallback(
(e) => {
@@ -44,6 +65,10 @@ const MapView = () => {
>
+
+ {/* Custom layers */}
+
+
);
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 9dfc1c0..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/store/map-actions.js b/src/store/map-actions.js
new file mode 100644
index 0000000..21a8e14
--- /dev/null
+++ b/src/store/map-actions.js
@@ -0,0 +1,25 @@
+import { mapActions } from "./map-slice";
+import poiGeojson from "../assets/data/poi.geojson";
+
+export const fetchPoiGeojson = () => {
+ return async (dispatch) => {
+ const fetchData = async () => {
+ const response = await fetch(poiGeojson);
+
+ if (!response.ok) {
+ throw new Error("Could not fetch poi data from static file!");
+ }
+
+ const data = await response.json();
+ return data;
+ };
+
+ try {
+ const poiGeojson = await fetchData();
+ dispatch(mapActions.setPoiGeojson(poiGeojson));
+ } catch (error) {
+ // TODO: ui error notification
+ console.error(error);
+ }
+ };
+};
diff --git a/src/store/map-slice.js b/src/store/map-slice.js
index 7a19746..789338e 100644
--- a/src/store/map-slice.js
+++ b/src/store/map-slice.js
@@ -13,32 +13,31 @@ const defaultMapStyle = {
sources: {
stamen_toner: {
type: "raster",
- tiles: [
- "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
- ],
+ tiles: ["https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png"],
tileSize: 256,
- attribution: 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL.',
+ attribution:
+ 'Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL.',
},
},
sprite: "",
glyphs: "https://yuchuntsao.github.io/fonts/{fontstack}/{range}.pbf",
layers: [
{
- "id": "background",
- "type": "background",
- "minzoom": 0,
- "paint": {
- "background-color": "rgba(255, 255, 255, 1)"
- }
+ id: "background",
+ type: "background",
+ minzoom: 0,
+ paint: {
+ "background-color": "rgba(255, 255, 255, 1)",
+ },
},
{
id: "stamen_toner",
type: "raster",
source: "stamen_toner",
paint: {
- 'raster-opacity': 0.3
- }
- }
+ "raster-opacity": 0.3,
+ },
+ },
],
};
@@ -47,11 +46,15 @@ const mapSlice = createSlice({
initialState: {
viewState: defaultViewState,
mapStyle: defaultMapStyle,
+ poiGeojson: null,
},
reducers: {
setViewState(state, action) {
state.viewState = action.payload;
- }
+ },
+ setPoiGeojson(state, action) {
+ state.poiGeojson = action.payload;
+ },
},
});
diff --git a/src/utils/icons.js b/src/utils/icons.js
new file mode 100644
index 0000000..b19d036
--- /dev/null
+++ b/src/utils/icons.js
@@ -0,0 +1,32 @@
+import beer from "../assets/icons/beer.svg";
+import bread from "../assets/icons/bread.svg";
+import burger from "../assets/icons/burger.svg";
+import cafe from "../assets/icons/cafe.svg";
+import cake from "../assets/icons/cake.svg";
+import drink from "../assets/icons/drink.svg";
+import fruit from "../assets/icons/fruit.svg";
+import general_restaurant from "../assets/icons/general_restaurant.svg";
+import japanese_restaurant from "../assets/icons/japanese_restaurant.svg";
+import shop from "../assets/icons/shop.svg";
+import sports from "../assets/icons/sports.svg";
+import trend_micro from "../assets/icons/trend_micro.svg";
+import wine from "../assets/icons/wine.svg";
+
+// Collect all icons into an object
+const icons = {
+ beer: beer,
+ bread: bread,
+ burger: burger,
+ cafe: cafe,
+ cake: cake,
+ drink: drink,
+ fruit: fruit,
+ general_restaurant: general_restaurant,
+ japanese_restaurant: japanese_restaurant,
+ shop: shop,
+ sports: sports,
+ trend_micro: trend_micro,
+ wine: wine,
+};
+
+export default icons;