웹 애플리케이션은 지도를 포함함으로써 사용자에게 귀중한 위치 기반 정보를 제공함으로써 큰 이점을 얻었습니다. 지도는 익숙하지 않은 장소를 탐색하는 것에서부터 근처 식당을 찾는 것까지 우리와 세상과의 상호 작용을 변화시켰습니다. 결과적으로 최근에는 웹사이트에 지도를 통합하는 것이 점점 더 대중화되고 있습니다. 그럼에도 불구하고 기능적이고 사용자 친화적인 지도를 디자인하는 것은 특히 이 분야에 대한 경험이 부족한 사람들에게는 어려울 수 있습니다. 이 글에서는 브라우저 내에서 효과적인 지도를 만드는 방법에 대한 유용한 팁을 공유하겠습니다.
기술에 대해 논의해 봅시다. 지도 작업을 할 때 일반적으로 세 가지 레이어를 사용합니다.
버튼과 양식을 포함하는 사용자 인터페이스를 렌더링합니다. 우리 스택에서는 React가 이 역할을 수행합니다.
지도를 렌더링하고 사용자 상호작용을 활성화합니다. 이를 위해 Mapbox를 사용합니다.
마커 또는 다각형에 대한 정보와 같은 데이터를 서버에서 가져옵니다. 데이터를 검색하기 위해 브라우저에 내장된 가져오기 기능을 사용합니다.
지도 작업 시 기술 스택을 더 잘 이해하기 위해 각 항목을 검토해 보겠습니다.
그만큼
페이지의 요소를 변경하는 것은 브라우저에 있어서 가장 비용이 많이 드는 작업이므로 최대한 효율적으로 수행하는 것이 중요합니다. 이 문제를 해결하기 위해 Facebook 엔지니어는 페이지에서 요소를 빠르고 간단하게 변경할 수 있는 React 라이브러리를 개발했습니다. 페이지에서 신속한 상태 변경을 제공하는 것 외에도 React를 사용하면 DOM 요소를 직접 사용하지 않고도 선언적으로 이를 수행할 수 있습니다. 대신에 우리는 일반적으로 추상화를 사용합니다.
// It's our state. Is the user our friend or not? // false by default const [isFriend, setIsFriend] = useState(false) // Depending on the state, we show the text on the button const buttonText = isFriend ? 'Your my Friend' : 'Add as Friend' // There is JSX, syntax for UI // In this case, we display a button, when clicked, we change the state return ( <button onClick={() => setIsFriend(true)}>{buttonText}</button> )
계층 구조의 맨 아래에 있는 양식, 버튼, 입력과 같은 일반 DOM 요소와 구성 요소를 중첩할 수 있습니다. 이러한 간단한 요소를 조합하여 완전한 형태와 같은 더 복잡한 요소를 만들 수 있습니다.
const Form = () => ( <form> <input name="Email"/> <input name="Password"/> </form> ) const App = () => ( <main> <h1>My form!</h1> <Form /> </main> )
React는 지도의 맥락에서 우리를 어떻게 지원하나요? 페이지의 지도는 버튼이나 양식과 유사하게 대화형이므로 지도 클릭과 같은 이벤트를 통해 렌더링 및 상호 작용을 최적화하는 것을 목표로 합니다. React는 이러한 최적화를 달성하는 데 도움이 될 수 있습니다. 작동 방식의 예는 다음과 같습니다.
// Use React to render the map with different event handlers // and render markers return ( <BaseMap onInitMap={() => console.log('I am alive!')} onClickMap={() => console.log('Click!')} onDestroyMap={() => console.log('Oh no!')} > <ClustersMarkers /> <PostsMarkers /> <ListingsMarkers /> </BaseMap> )
React로 작업할 때 페이지 요소의 효율적인 조작, 빠른 변경, 이벤트를 통한 상호 작용이 가능하다는 점을 기억하는 것이 중요합니다. 이는 HTML과 유사한 추상화를 통해 달성되므로 단순한 구성 요소에서 복잡한 구성 요소를 쉽게 만들 수 있습니다.
이제 지도 자체에 대해 논의해 보겠습니다. 지도를 만들고 사용하는 것은 어려울 수 있으며 소수의 제품 회사만이 처음부터 지도를 디자인할 수 있습니다. 일반적으로 대부분의 사람들은 시도와 테스트를 거쳐 사용자 친화적인 API가 포함된 미리 만들어진 라이브러리에 의존합니다.
Google Maps, Leaflet, Bing Maps, Mapbox 등 다양한 동적 지도 제공업체를 사용할 수 있습니다. 그러나 우리는 다음에 중점을 둘 것입니다.
Mapbox 제공
또한 Mapbox는 다음을 제공합니다.
Mapbox는 다양한 기능을 제공합니다.
Mapbox 지도를 다시 살펴보겠습니다. 무엇을 하는가?
페이지의 HTML 요소에서 지도를 초기화합니다.
지도를 구성하는 이미지를 로드하고 렌더링합니다.
GeoJson을 입력 데이터로 사용하여 마커와 같은 추가 요소를 그립니다.
클릭이나 확대/축소 변경과 같은 처리할 수 있는 이벤트를 생성합니다.
각 항목을 자세히 살펴보겠습니다.
Mapbox는 타일을 사용한 지도 렌더링을 전문으로 합니다. 타일은 더 큰 지도를 구성하는 작은 정사각형 이미지입니다. 타일의 기본 크기는 512x512픽셀이며 다음 중 하나일 수 있습니다.
아시다시피 Mapbox Studio를 사용하면 지도 타일에 포함하려는 특정 데이터를 선택할 수 있습니다. 그런 다음 이 타일을 다음 위치에 배치합니다.
<canvas width="100" height="100" />
Mapbox는 타일의 로드, 삽입 및 업데이트를 처리합니다. 우리가 해야 할 일은 지도를 표시할 위치와 확대/축소 수준이나 지도 좌표와 같은 초기 조건을 지정하는 것뿐입니다. Mapbox를 사용하려면
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN'; const map = new mapboxgl.Map({ container: 'map', // we can use an Id or an element style: 'mapbox://styles/mapbox/streets-v11', // URL for styles center: [-74.5, 40], // initial coordinates [lng, lat] zoom: 9, // initial zoom });
그 후에는 ID가 'map'인 요소의 페이지에 지도가 표시됩니다.
사용자에게 지도에 더 많은 정보를 제공하기 위해 당사는 특정 시설의 위치나 특정 지역의 경계를 표시하는 경우가 많습니다. 이를 달성하기 위해 우리는 다음과 같은 특정 데이터 형식을 사용합니다.
GeoJSON은 지도에 지리 구조를 저장하기 위한 표준 형식입니다. 주소, 위치, 거리, 고속도로, 국경, 국가, 주 및 이들의 조합(멀티파트)과 같은 지리적 객체를 설명하는 다양한 기본 유형을 저장할 수 있습니다. GeoJSON은 2008년에 도입되었으며 다음과 같이 표현됩니다.
{ "type": "Feature", // also can be FeatureCollection, it's collection of Feature "geometry": { "type": "Point", // also can be LineString, Polygon, MultiPolygon "coordinates": [125.6, 10.1] // for other types you can use Array with coordinates }, "properties": { // it's metadata, we can you that to show something on the map "name": "Dinagat Islands" } }
Mapbox에서 사용되는 좌표계에 대해 이야기해 보겠습니다. 기본적으로 Mapbox는 다음을 사용합니다.map.setProjection
메소드를 사용할 수 있습니다.
이제 지도에 GeoJSON을 표시하는 방법에 대해 설명하겠습니다. Mapbox는 도움이 될 두 가지 엔터티를 제공합니다.
지도에 다각형이나 마커를 표시하려면 서버에서 GeoJson 형식의 데이터를 검색해야 합니다. 그런 다음 소스를 생성하고 데이터를 입력한 후 필요한 레이어에 연결합니다.
const geoJsonFeature = { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ [-67.13734, 45.13745], [-66.96466, 44.8097], [-68.03252, 44.3252], [-67.13734, 45.13745] ] } } // Create source with our data map.addSource('ourSource', { 'type': 'geojson', 'data': geoJsonFeature }); // Add layer for background map.addLayer({ 'id': 'background', 'type': 'fill', 'source': 'ourSource', // название нашего source 'layout': {}, 'paint': { 'fill-color': '#0080ff', 'fill-opacity': 0.5 } }); // Add layer for border map.addLayer({ 'id': 'border', 'type': 'line', 'source': 'ourSource', 'layout': {}, 'paint': { 'line-color': '#000', 'line-width': 3 } });
이 코드를 실행하면 다음과 같은 결과를 얻습니다.
이 주제에 대해 자세히 알아보려면 다음을 참조하세요.on
메소드를 호출하기만 하면 됩니다.
map.on('mousemove', (e) => { console.log(JSON.stringify(e.point)); }); // Result: {"x":330,"y":49}
요약하면, 우리가 기억해야 할 것은 무엇입니까? Mapbox를 사용하면 지도를 표시하고 그 위에 데이터를 그리고 지도 이벤트를 처리할 수 있습니다. 동시에 Mapbox는 이미지(타일) 로드 및 표시를 관리합니다.
에 대해 한마디
무엇을 기억해야 할까요? 서버에서 데이터를 검색하고 이를 위한 많은 라이브러리가 있지만 가져오기를 사용하겠습니다. 다음으로, 뉘앙스가 있으므로 지도 작업 시 구체적으로 이를 수행하는 방법을 살펴보겠습니다.
이제 위에 설명된 기술이 어떻게 함께 작동하는지 살펴보겠습니다. 먼저 fetch를 사용하여 다각형을 표시하기 위한 데이터를 검색합니다. 그런 다음 지도 초기화를 선언하고 지도가 로드된 후 지도에 다각형을 추가합니다.
다음 사이트에서도 실제 사례를 찾을 수 있습니다.
const useFetch = () => { /* Our data { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ [ [-67.13734, 45.13745], [-68.03252, 44.3252], [-68.90478, 47.18479], [-67.13734, 45.13745], ] ] } } */ const [data, setData] = useState(null) useEffect(() => { fetch('https://our-api.com/polygon') .then(response => response.json()) .then(setData) .catch(e => { console.error(e) }) }, [setData]) return { data } } const BaseMap = () => { // Use the hook to fetch data const { data } = useFetch(GET_REGION); // Map instance const map = useRef(null); // DOM element const mapContainer = useRef(null); // Main logic - init the map and add the event useEffect(() => { if (map.current) { return; // initialize map only once } mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN'; map.current = new mapboxgl.Map({ container: mapContainer.current, style: 'mapbox://styles/mapbox/light-v10', // style URL (it's Mapbox's core style) center: [-68.137343, 45.137451], // starting position zoom: 5 // starting zoom }); // Handle event map.on('load', () => { const sourceId = 'source-region' // Add a data source containing GeoJSON data map.addSource(sourceId, { 'type': 'geojson', 'data': data.region // our data from Apollo }); // Add a new layer to visualize the polygon map.addLayer({ 'id': 'background', 'type': 'fill', 'source': sourceId, // reference the data source 'paint': { 'fill-color': '#0080ff', // blue color fill 'fill-opacity': 0.5 } }); // Add a black outline around the polygon map.addLayer({ 'id': 'outline', 'type': 'line', 'source': sourceId, 'paint': { 'line-color': '#000', 'line-width': 3 } }); }); }); return <div ref={mapContainer} />; }
우리는 미래 아키텍처를 뒷받침하는 기술 스택을 살펴보았습니다. 다음 기사에서는 지도 아키텍처를 설계하는 데 도움이 되는 원칙, 모듈의 최대 낮은 결합도와 높은 응집도를 달성하는 방법, 확장 가능한 지도 시스템을 유지하고 개발하는 방법에 대해 설명합니다.
많은 관심을 가져주셔서 감사합니다! 좋은 하루 보내세요.