GIS

Folium: 아이콘 링크에 슬라이드 효과 적용하기

유병혁 2022. 9. 21. 12:31

안녕하세요? 이번 글은 Folium에서 아이콘 링크에 슬라이드 효과를 적용하는 방법을 소개해 보겠습니다. 참고로 이 글은 월악산국립공원을 대상으로 한 '자연관찰로 GPS 탐방 콘텐츠 개발' 과정에서 자체 제작한 웹사이트의 내용을 일부 정리한 것입니다.

 

자, 그럼 시작해 보겠습니다. 일단 HTML/CSS로 제작된 슬라이드 효과 소스코드는 '코남' 님이 제공하시는 아래 글을 참고하였습니다. 유용한 자료 공유에 감사드립니다.

 

스크립트 없이 HTML과 CSS로만 만드는 슬라이드효과 /*코딩*/ [HTML+CSS{ 코남} ]

#HTML #CSS #INPUT #LABEL #웹 #비쥬얼 #아트 #코딩 #코남 #코딩하는남자 #슬라이드효과 ...

blog.naver.com

먼저 Folium과 Pandas 모듈을 호출하겠습니다.

import folium
from folium import plugins
from folium.features import CustomIcon
from folium import IFrame
import pandas as pd

위경도 좌표를 포함한 데이터를 열어보겠습니다. *해당 데이터와 소스코드는 깃허브에 올려놨습니다.

url = "https://raw.githubusercontent.com/osgeokr/exploreKNP/main/data/{}".format
df = pd.read_csv(url("explore_list.csv"), encoding='utf-8')
df

GPS 탐방 콘텐츠는 크게 탐험가코스, 도전자코스, 어린이코스로 구분되는데요, 이 값은 'CAT_KO' 필드의 고유값을 확인해 보시면 알 수 있습니다.

# 고유값
df['CAT_KO'].unique()

코스별 변수를 정의합니다. 이 중 'Children(어린이코스)'를 위주로 정리해 보겠습니다. 'LAT' 필드는 위도, 'LON' 필드는 경도를 포함하며, 이 값을 통해 매핑이 가능합니다.

df_explorer = df[df['CAT_EN']=='Explorer'] # Explorer(탐험가코스)
df_challenger = df[df['CAT_EN']=='Challenger'] # Challenger(도전자코스)
df_children = df[df['CAT_EN']=='Children'] # Children(어린이코스)
df_children.head()

'NUM' 필드에서 'S'는 시점을, 'E'는 종점을 뜻하며 'P'는 해당 지점을 나타냅니다. 그리고 각 지점마다 아래와 같이 '_1', '_2'와 같은 이름으로 된 이미지 파일이 준비되어 있습니다. *아이콘을 비롯한 지도 웹사이트용 이미지 작업은 '에코샵홀씨(https://www.wholesee.com/)에서 제작해 주셨습니다.

앞서 소개드린 HTML/CSS 슬라이드 효과 소스를 참고하여 함수를 정의해 줍니다. 예를 들어 point_html3()는 이미지가 3개인 경우, 데이터 경로(url)와 고유코드(num)를 전달받아 슬라이드 효과를 구현해 주는 소스코드입니다. 코남 님이 제공해 주신 소스를 다음과 같이 약간 변경, 적용했습니다.

def point_html3(url, num):
    return """
    <div class="section">
        <input type="radio" name="slide" id="slide01" checked>
        <input type="radio" name="slide" id="slide02">
        <input type="radio" name="slide" id="slide03">

        <div class="slidewrap">
            <ul class="slidelist">
                <li>
                    <a>
                        <label for="slide01" class="left"></label>
                            <img src=\"""" + url(num + "_01.png") + """\" >
                        <label for="slide02" class="right"></label>
                    </a>
                </li>
                <li>
                    <a>
                        <label for="slide01" class="left"></label>
                            <img src=\"""" + url(num + "_02.png") + """\" >
                        <label for="slide03" class="right"></label>
                    </a>
                </li>
                <li>
                    <a>
                        <label for="slide02" class="left"></label>
                            <img src=\"""" + url(num + "_03.png") + """\" >
                        <label for="slide03" class="right"></label>
                    </a>
                </li>
            </ul>
        </div>
    </div>
    <style>
        * {margin:0;padding:0;}
        .section input[id*="slide"] {display:none;}

        .section .slidewrap {max-width:240px;margin:0 auto;overflow:hidden;}
        .section .slidelist {white-space:nowrap;font-size:0;}
        .section .slidelist > li {display:inline-block;vertical-align:middle;width:100%;transition:all .5s;}
        .section .slidelist > li > a {display:block;position:relative;}
        .section .slidelist > li > a img {width:100%;}

        .section .slidelist label {position:absolute;z-index:1;top:50%;transform:translateY(-50%);padding:25px;cursor:pointer;}
        .section .slidelist .left {left:10px;background:url(\"""" + url("left.png") + """\") center center / 20% no-repeat;}
        .section .slidelist .right {right:10px;background:url(\"""" + url("right.png") + """\") center center / 20% no-repeat;}

        .section input[id="slide01"]:checked ~ .slidewrap .slidelist > li {transform:translateX(0%);}
        .section input[id="slide02"]:checked ~ .slidewrap .slidelist > li {transform:translateX(-100%);}
        .section input[id="slide03"]:checked ~ .slidewrap .slidelist > li {transform:translateX(-200%);}
    </style>
    """

자, 이제 Folium으로 매핑 후 아이콘 링크에 슬라이드 효과 함수를 연결해 주면 되겠습니다.

# 타일 유형
m = folium.Map(location=[df.LAT.mean(), df.LON.mean()], zoom_start=16, tiles=None)
folium.raster_layers.TileLayer(tiles='CartoDB positron', name='GPS탐방로').add_to(m)
m

'Children(어린이코스)'를 다음과 같이 정의합니다.

# Children(어린이코스)
f_children = folium.FeatureGroup(name='어린이코스', overlay=True, show=True)
for index, row in df_children.iterrows():
    # 아이콘
    icon = CustomIcon(url("Children.png"), icon_size=(50, 50))
    # 팝업
    if row['NUM'].startswith('S') == True: # 시점
        html = start_html(url, row['NUM'])
        popup = folium.Popup(folium.Html(html, script=True), min_width=240, max_width=240)
    elif row['NUM'] == 'P2':
        html = point_html6(url, row['NUM'])
        popup = folium.Popup(folium.Html(html, script=True), min_width=240, max_width=240)
    elif row['NUM'] == 'E0': # 종점
        html = point_html4(url, row['NUM'])
        popup = folium.Popup(folium.Html(html, script=True), min_width=240, max_width=240)
    else:
        html = point_html3(url, row['NUM'])
        popup = folium.Popup(folium.Html(html, script=True), min_width=240, max_width=240)
    # 마커
    folium.Marker(location=[row['LAT'], row['LON']], icon=icon, popup=popup).add_to(f_children)
    # 폴리라인
    folium.PolyLine(locations=df_children[['LAT', 'LON']].iloc[:-1 , :].values.tolist(),
                    weight=20, color='#1DA462', opacity=0.5).add_to(f_children)
m.add_child(f_children)
m

결과는 다음과 같습니다. 산양 아이콘을 클릭하면, 해당 지점의 슬라이드 효과가 안내됩니다.

현재 위치, 코스를 확인할 수 있도록 '위치 콘트롤'과 '레이어 콘트롤'을 추가 후 'index.html' 파일로 저장해 주면 되겠습니다.

plugins.LocateControl().add_to(m) # 위치 컨트롤 추가
folium.LayerControl(collapsed=False).add_to(m) # 레이어 컨트롤 추가
m.save("index.html") # 파일로 저장
m

결과는 다음과 같습니다.

어린이코스, 도전자코스, 탐험가코스를 모두 정리한 결과 화면입니다. 아이 동반으로 월악산국립공원을 방문하시는 분들은 현장에서 직접 이용해 보셔도 좋겠습니다. :)