문서 / 기본 / GroundImage

GroundImage ― 이미지를 지도에 붙이기

남서・북동의 2점으로 범위를 정하고, 거기에 한 장의 이미지를 깝니다. 시설의 층 도면, 고지도, 항공사진, 직접 만든 색분류도 등, 타일화되지 않은 이미지를 그대로 지도에 겹칠 수 있습니다. 범위나 투명도는 나중에 바꿔 쓸 수 있고, 이미지는 카메라 조작에 따라가며 지면에 붙어 있는 채로 표시됩니다.

BOUNDS
SW / NE
IMAGE
image / url
OPACITY
0.0 – 1.0
TILE SIZE
512 · 타일 렌더링 시에만
플랫폼

01 · GroundImage의 상태

GroundImageState가 한 장의 이미지를 나타냅니다. 범위・이미지・투명도와, 탭 핸들러를 가집니다. 플랫폼마다 자연스러운 형태로 이미지를 넘길 수 있습니다(Android는 Drawable, iOS는 UIImage, Web은 URL).

GroundImageMapPageViewModel.kt · Jetpack Compose
val groundImageState =
    GroundImageState(
        id = "groundImage",
        bounds =
            GeoRectBounds(
                southWest = southWestPosition,
                northEast = northEastPosition,
            ),
        image = drawable,       // Drawable을 그대로 넘긴다
        opacity = 0.5f,
        onClick = this::onGroundImageClick,
    )

GroundImage(groundImageState)
프로퍼티
설명
bounds
이미지를 깔 사각형 범위. 남서와 북동의 2점으로 정합니다.
image / imageUrl
표시할 이미지. Android는 Drawable, iOS는 UIImage, Web은 이미지 URL로 넘깁니다.
opacity
불투명도. 0.0이면 완전히 투명, 1.0이면 불투명. 바탕 지도와 겹쳐 보이게 하고 싶을 때 낮춥니다.
tileSize
래스터 타일로 렌더링할 경우의 1타일의 변의 길이. 네이티브 이미지 오버레이로 렌더링되는 프로바이더에서는 쓰이지 않습니다. 기본값 512 그대로도 문제없습니다.
extra
임의의 부수 데이터. 탭 시에 받을 수 있습니다.
onClick
탭 핸들러. 이미지의 상태와 탭된 좌표를 받습니다.

02 · 범위와 투명도

범위는 사각형입니다. 이미지의 종횡비와 범위의 종횡비가 다른 경우에는 범위에 맞춰 늘어나므로, 붙이고 싶은 도면의 종횡비에 맞춘 범위를 지정하세요. 범위・투명도・이미지는 모두 나중에 바꿔 쓸 수 있고, 바꿔 쓴 시점에 렌더링에 반영됩니다.

SW
NE
남서(SW)와 북동(NE) 두 점으로 사각형이 정해집니다. 그림의 테두리와 마커는 샘플 앱 쪽 구현입니다.
BOUNDS

드래그로 범위를 다시 만들기

2점의 마커를 드래그하면서 bounds를 교체하면, 이미지가 따라옵니다. 다만 연속 갱신의 추종성은 프로바이더에 따라 차이가 있습니다.

OPACITY

바탕 지도와 겹치기

투명도를 낮추면, 아래 지도의 도로나 지명이 비쳐 보입니다. 엔진에 따라서는 변경의 타이밍이나 듣는 방식에 제한이 있습니다.

샘플 · 고지도를 범위에 맞춰 겹친 모습
범위와 투명도를 바꾸기
// 모서리 마커를 드래그해 bounds를 다시 만든다
override fun onMarkerDrag(dragged: MarkerState) {
    when (dragged.id) {
        "south_west" -> southWestPosition = GeoPoint.from(dragged.position)
        "north_east" -> northEastPosition = GeoPoint.from(dragged.position)
    }
    bounds = GeoRectBounds(southWest = southWestPosition, northEast = northEastPosition)
}

// 불투명도는 단순 대입
groundImageState.opacity = sliderOpacity

03 · 어느 프로바이더에서도 같게 보인다

GroundImage는 각 지도 SDK 드라이버 중에서 구현 차이가 가장 큰 기능입니다. 이미지 오버레이의 구조는 엔진마다 크게 다르고, 동등한 기능을 갖지 않는 것도 있습니다. MapConductor는 가능한 범위에서 이 차이를 흡수하지만, 프로바이더에 따라서는 동적인 변경에 제한이 남습니다.

PLACEMENT

같은 범위・같은 늘이기

이미지는 지정한 범위에 맞춰 배치됩니다. 엔진 쪽 이미지 오버레이의 좌표계 차이와 관계없이, 같은 위치・같은 크기로 표시됩니다.

NATIVE FIRST

먼저 네이티브의 기능으로 그린다

각 드라이버는 가능한 한 그 지도 SDK 고유의 이미지 오버레이 기능을 써서 최적으로 그립니다(ArcGIS라면 MediaLayer + ImageElement, Cesium이라면 Rectangle의 이미지 머티리얼 등). 아무래도 동등한 기능이 없는 엔진에 한해, 이미지를 잘라 타일로 공급하고 래스터 레이어로 겹칩니다. 어느 경로에서도 앱 쪽의 코드는 달라지지 않습니다.

LIMITATIONS

프로바이더에 따른 제한

범위의 재구성(드래그 중의 연속 갱신)이나 투명도의 변경이, 엔진 쪽 제약으로 제한적이 되는 경우가 있습니다. 정적인 배치는 어느 프로바이더에서도 같지만, 동적으로 바꾸는 용도에서는 대상 프로바이더에서의 확인을 권합니다.

HIT TEST

탭 판정도 공통

탭 판정은 공통 로직으로 하기 때문에, 엔진이 이미지 오버레이의 탭을 지원하는지 여부와 관계없이 onClick이 호출됩니다.

04 · 탭

onClick은 이미지의 상태와, 탭된 좌표를 받습니다. 샘플에서는 탭으로 이미지 자체를 교체해 표시를 전환합니다.

탭으로 이미지를 교체하기
// 탭하면 이미지를 바꾼다
override fun onGroundImageClick(clicked: GroundImageEvent) {
    val isBase = clicked.state.image == imageResources.image
    image = if (isBase) imageResources.clickedImage else imageResources.image
}
event.state

탭된 이미지의 상태. 현재의 이미지나 extra를 참조할 수 있습니다.

event.clicked

탭된 지리 좌표. 범위 안의 어디가 눌렸는지 알 수 있습니다.

이미지의 투명한 부분도 탭 범위에 포함됩니다. 투명 부분을 무반응으로 하고 싶은 경우에는, 범위를 이미지의 실체에 맞추거나 폴리곤을 병용하세요.

관련 페이지