w3HexSchool
. leaflet.js
. react
最近
武漢肺炎(2019-nCoV)
疫情爆發 , 大家瘋搶口罩 ,
為了方便查詢藥局的現有口罩數量 , 六角學院舉辦口罩地圖
的製作活動 !在下參加了這個活動 , 以下是小弟的製作過程
使用
create-react-app
建立
yarn add leaflet
leaflet
& leaflet.css
import "leaflet/dist/leaflet.css";
import L from "leaflet";
const OSMUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
L.tileLayer(OSMUrl).addTo(mymap);
完整的
App.js
// App.js
import React from "react";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
// 參考資料 : https://leafletjs.com/examples/quick-start/ & https://juejin.im/post/5cc192976fb9a032092e8e0a
class LeafletMap extends React.Component {
componentDidMount() {
const mymap = L.map("mapid").setView([25.03418, 121.564517], 17);
const OSMUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
L.tileLayer(OSMUrl).addTo(mymap);
// 使用 leaflet-color-markers ( https://github.com/pointhi/leaflet-color-markers ) 當作 marker
const greenIcon = new L.Icon({
iconUrl:
"https://cdn.rawgit.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png",
shadowUrl:
"https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
const marker = L.marker([25.03418, 121.564517], { icon: greenIcon }).addTo(
mymap
);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
L.circle([25.03418, 121.564517], {
color: "red",
fillColor: "#f03",
fillOpacity: 0.5,
radius: 10
}).addTo(mymap);
}
render() {
// 設定 height 顯示地圖 ( 預設值 height : 0 )
return <div id="mapid" style={{ height: "100vh", width: "100vw" }} />;
}
}
export default LeafletMap;
結果 : 地圖呈現
口罩數量
口罩數量 : https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json
我們將預設的 下三角 拿掉 , 並控制不要有 padding 的產生
.popupCustom .leaflet-popup-tip {
display: none;
}
.popupCustom .leaflet-popup-close-button {
display: none;
}
.popupCustom .leaflet-popup-content-wrapper {
background: transparent;
color: transparent;
}
.popupCustom .leaflet-popup-content-wrapper .leaflet-popup-content {
margin: 0;
}
className
marker.bindPopup(content, {className: 'popupCustom'});
tailwind.css
// src/index.js
+ import './styles/tailwind.css';
// Tooltip.js
import React from "react";
import Styles from "./Tooltip.module.css";
const Tooltip = ({medicalStore}) => (
<div className={Styles.card_root}>
<div className={Styles.text_root}>
<div className='pb-4'>
<span className={Styles.text_name}>{medicalStore.name}</span>
</div>
<div className='pb-4'>
<span className={Styles.text_address}>
{medicalStore.address}
</span>
</div>
<div className='flex'>
<div className='flex-1 flex items-center'>
<img className='px-4' height='12px' src={clockSvg} alt="時鐘 : "/>
<span className={Styles.time_letter}>{medicalStore.time}</span>
</div>
<div className='flex-1 flex items-center'>
<img className='px-4' src={phoneSvg} height='12px' alt="電話 : "/>
<span className={Styles.phone_letter}>{medicalStore.phone}</span>
</div>
</div>
</div>
<div className='flex'>
<div className={Styles.adult_mask}>
<div>成人口罩數量</div>
<div className='w-full flex items-end pt-4'>
<div className='flex flex-1 justify-center items-center'>
<img src={adultFaceSvg} height='37px' alt="成人頭像"/>
</div>
<div>
<span className='text-16 pr-4'>{medicalStore.leftMask.adult}</span> 個
</div>
</div>
</div>
<div className={Styles.children_mask}>
<div>兒童口罩數量</div>
<div className='w-full flex items-end pt-4'>
<div className='flex flex-1 justify-center items-center'>
<img src={childFaceSvg} height='40px' alt="兒童頭像"/>
</div>
<div>
<span className='text-16 pr-4'>{medicalStore.leftMask.children}</span> 個
</div>
</div>
</div>
</div>
</div>
);
export default Tooltip;
/* Tooltip.module.css */
.adult_mask {
border-bottom-left-radius: 5px;
display: flex;
flex: 1;
flex-direction: column;
color: #fdfdfe;
padding: 8px;
background-color: #06b66c;
}
.children_mask {
border-bottom-right-radius: 5px;
display: flex;
flex: 1;
flex-direction: column;
color: #fdfdfe;
padding: 8px;
background-color: #faa23f;
}
.text_name {
color: #848484;
font-size: 20px;
font-weight: 900;
}
.text_address {
color: #ababab;
font-size: 11px;
font-weight: 700;
}
.time_letter,
.phone_letter {
color: #ababab;
font-size: 10px;
letter-spacing: 2px;
}
.card_root {
width: 300px;
background-color: #fff;
border-radius: 6px;
border: 1px solid rgba(0, 0, 0, 0.3);
/* Position the tooltip */
position: absolute;
z-index: 1000;
bottom: calc(100% + 10px);
left: 50%;
margin-left: -150px;
display: flex;
flex-direction: column;
}
.text_root {
padding: 8px 14px 8px 14px; /* (top, right, bottom, and left) */
}
目標示意圖
使用 marker.bindPopup( string ) 來顯示上面格式化後的 Popup
並且利用 ReactDOMServer.renderToString 將 ReactElement 轉換成 string
卡斯柏的口罩地圖教學共筆 : https://paper.dropbox.com/doc/2020-0213-2XPGbqH5JqE9vTD7a6npd