Camera

Camera 개념 및 조작 방법.

지도는 X, Y평면을 카메라가 내려다보는 형태로 구성되어 있습니다. 카메라가 내려다보는 높이에 따라 줌레벨이 결정됩니다. 줌레벨의 값이 커질수록 지도가 확대되어 자세하게 표현됩니다.

Camera Property


기본적인 카메라를 조작하는 Property는 position, tilt, rotation이 있습니다.

Property Description
position 지도 평면을 카메라가 바라볼 위치를 위미합니다. MapPoint로 지정할 수 있습니다.
tilt 지도 평면을 카메라가 바라봤을 때, 카메라의 기울임 각도를 의미합니다. 수직방향의 radian이 단위이며, tilt값을 조절하면 2d평면이 3d로 표현되며, 더 먼곳을 표시할 수 있습니다.
rotation 지도 평면을 카메라가 바라봤을 때, 카메라의 회전 각도를 의미합니다. 정북기준 시계방향 radian이 단위입니다.

또한, KakaoMap 객체에서 현재 카메라의 여러 상태값을 받아오거나 설정할 수 있습니다.

Property Description
minLevel KakaoMap의 최소 줌레벨을 의미합니다.
maxLevel KakaoMap의 최대 줌레벨을 의미합니다.
cameraMinLevel 카메라의 최소 줌레벨을 의미합니다. 해당 레벨보다 작은 레벨로는 카메라 줌레벨을 축소시킬 수 없습니다.
zoomLevel 현재 KakaoMap의 줌레벨을 가져옵니다.
cameraAnimationEnabled 카메라 애니메이션 활성화 상태를 지정합니다. false로 설정하면 animateCamera()를 호출해도 애니메이션 없이 즉시 이동됩니다.
cameraHeight 현재 KakaoMap의 카메라 높이값을 가져옵니다.

CameraUpdate


CameraUpdate 클래스를 이용하여 다양한 방법으로 카메라를 조작할 수 있습니다. CameraUpdate 클래스는 생성 방법에 따라 여러 종류의 make 함수를 제공합니다.

카메라의 위치 및 각도를 지정한 CameraPosition, 화면에 보일 범위를 지정하는 AreaRect, 현재 위치로부터 지정된 offset만큼만 이동하는 CameraTransfrom등 다양한 make 함수를 제공합니다.

아래 코드는 특정 지점, 레벨, 회전, 틸트를 특정값으로 지정하여 CameraUpdate를 생성하는 예시입니다.

	//특정 지점, 레벨, 회전, 틸트로 이동하는 CameraUpdate를 생성.
	let cameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 126.978862, latitude: 37.546086), zoomLevel: 15, rotation: 1.7, tilt: 0.0, mapView: view)

CameraPosition

CameraPosition은 카메라의 위치를 지정하기 위한 클래스로, 카메라가 바라보는 카메라 시야 범위의 중심점 위치 및 각도로 표현합니다.

CameraPosition을 구성하는 Property는 아래와 같습니다.

Property Description
targetPoint 카메라가 바라보는 지점의 MapPoint
height 카메라 높이(m)
rotation 카메라 회전각 (radian. 정북기준 시계방향)
tilt 카메라의 기울임각 (radian. 수직방향 기준)

아래 코드는 CameraPosition을 사용하여 camera를 이동시키는 예제입니다.

func moveCamera() {
	let mapView: KakaoMap = mapController?.getView("mapview") as! KakaoMap
	
	// CameraUpdateType을 CameraPosition으로 생성하여 지도의 카메라를 특정 좌표로 이동시킨다. MapPoint, 카메라가 바라보는 높이, 회전각 및 틸트를 지정할 수 있다.
	mapView.moveCamera(CameraUpdate.make(cameraPosition: CameraPosition(target: MapPoint(longitude: 127.036933, latitude: 37.500816), height: 0, rotation: 0, tilt: 0)))
	
}

AreaRect

AreaRect는 지도상의 특정 사각형 범위를 나타내기 위한 클래스로, 서남쪽과 북동쪽 좌표를 각각 좌하단 우상단으로 하는 정방형 범위를 의미합니다. 특정 범위를 모두 포함하여 지도에 꽉차게 보여주고자 할 때, 사각형 범위를 지정할 수 있습니다.

직접 사각형의 범위를 지정할수도 있지만, 특정 points를 모두 포함하는 AreaRect 범위를 구하는 인터페이스도 제공합니다.

AreaRect를 구성하는 Property는 아래와 같습니다.

Property Description
southWest AreaRect의 서남쪽 MapPoint
northEast AreaRect의 동북쪽 MapPoint

아래 예제는 특정 points를 모두 포함하는 AreaRect 범위를 구하는 예제입니다.

func createAreaRect() {
	let view = mapController?.getView("mapview") as! KakaoMap
        var points:[MapPoint] = [MapPoint]()
        
        for poi in _pois {
            poi.show()
            points.append(poi.position()!)
        }
        
        // 특정 범위가 모두 보이는 최대레벨의 위치로 카메라를 이동시키는 CameraUpdate를 생성한다.
        let cameraUpdate = CameraUpdate.make(area: AreaRect(points: points))
        view.animateCamera(cameraUpdate: cameraUpdate, options: CameraAnimationOptions(autoElevation: true, consecutive: true, durationInMillis: 2000))
}

CameraTransform

CameraTransform은 카메라의 위치 및 각도의 변화량을 지정하는 클래스입니다. 카메라의 절대적인 위치 및 각도가 아니라, 현재 위치 및 각도로부터 얼마나 이동/회전할지에 대한 변화량을 지정할 때 사용하는 클래스입니다.

CameraTransform의 Property는 아래와 같습니다.

Property Description
deltaPos 카메라가 바라보는 위치 변화량. MapPoint 기준이므로 경위도좌표계의 변화량.
deltaHeight 카메라의 높이 변화량
deltaRotation 카메라의 회전각 변화량
deltaTilt 카메라의 기울임각 변화량

아래 예제는 CameraTransform을 이용하여 카메라를 이동시키는 예제입니다.

func createCameraTransform() {
	let mapView: KakaoMap = mapController?.getView("mapview") as! KakaoMap

	let cameraUpdate = CameraUpdate.make(transform: CameraTransform(deltaPos: CameraTransformDelta(deltaLon: 0.004491, deltaLat: -0.000898), deltaHeight: 0, deltaRotation: 0, deltaTilt: 0))
	mapView.moveCamera(cameraUpdate)
}

moveCamera / animateCamera


생성한 CameraUpdate로 지도위의 카메라를 조작할 수 있습니다. moveCamera 함수는 카메라를 즉시 이동시킬수 있고, animateCamera함수는 animation 효과를 주어 카메라가 이동하는 과정을 애니메이션으로 보여줄 수 있습니다.

아래 코드는 생성한 CameraUpdate로 카메라를 즉시 이동시키는 예제입니다.

//특정 지점, 레벨, 회전, 틸트로 이동하는 CameraUpdate를 생성.
let cameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 126.798662, latitude: 37.546086), zoomLevel: 15, rotation: 1.7, tilt: 0.0, mapView: view)
//애니메이션 없이 CameraUpdate에 지정된대로 카메라를 즉시 조정.
view.moveCamera(cameraUpdate)

아래 코드는 생성한 CameraUpdate로 카메라를 이동시키면서 애니메이션 효과를 주는 예제입니다.

//특정 지점, 레벨, 회전, 틸트로 이동하는 CameraUpdate를 생성.
let cameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 126.798662, latitude: 37.546086), zoomLevel: 15, rotation: 1.7, tilt: 0.0, mapView: view)
        
//지정한 CameraUpdate 대로 카메라 애니메이션을 시작한다.
//애니메이션의 옵션을 지정할 수 있다.
//autoElevation : 장거리 이동시 카메라 높낮이를 올려 이동을 잘 보이도록 하는 애니메이션.
//consecutive : animateCamera를 연속적으로 호출하는 경우, 각 애니메이션을 이어서 연속적으로 수행한다.
//durationInMiliis : 애니메이션 동작시간(ms).
view.animateCamera(cameraUpdate: cameraUpdate, options: CameraAnimationOptions(autoElevation: false, consecutive: true, durationInMillis: 2000))

Camera EventHandler 및 callback 이용하기


KakaoMapsSDK는 사용자가 카메라 움직임에 따라 부가적인 기능을 수행할 수 있도록 카메라 움직임에 관한 Callback및 EventHandler를 제공합니다.

CameraEventHandler

KakaoMap 클래스 내부의 Camera Event Handler를 이용하여 KakaoMap의 카메라 이동 시작/정지에 대한 핸들러를 추가할 수 있습니다. 핸들러는 CameraActionType을 파라미터로 전달하며, 이를 이용하여 카메라 이동 시작/정지 시점에 맞추어 핸들링 할 수 있습니다. 아래 예제는 KakaoMap에 카메라 이벤트 핸들러를 추가하는 예제입니다.

// 카메라 이동 관련 이벤트를 핸들링하는 예제
class CameraEventHandlerSample: APISampleBaseViewController {
    
    override func addViews() {
        let defaultPosition: MapPoint = MapPoint(longitude: 127.02768, latitude: 37.498254)
        let mapviewInfo: MapviewInfo = MapviewInfo(viewName: "mapview", viewInfoName: "map", defaultPosition: defaultPosition)
        
        mapController?.addView(mapviewInfo)
    }
    
    override func viewInit(viewName: String) {
        print("OK")
        
        // 카메라 이동 멈춤 핸들러를 추가한다.
        let mapView = mapController?.getView("mapview") as! KakaoMap
        _cameraStartHandler = mapView.addCameraWillMovedEventHandler(target: self, handler: CameraEventHandlerSample.cameraWillMove)
        _cameraStoppedHandler = mapView.addCameraStoppedEventHandler(target: self, handler: CameraEventHandlerSample.onCameraStopped)
    }
    
    // 버튼을 클릭하면 카메라를 지정한 위치로 이동시킨다.
    @IBAction func onButtonClicked(_ sender: Any) {
        let mapView = mapController?.getView("mapview") as! KakaoMap
        let cameraUpdate: CameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 126.798365, latitude: 37.566691), zoomLevel: 10, mapView: mapView)
        mapView.animateCamera(cameraUpdate: cameraUpdate, options: CameraAnimationOptions(autoElevation: true, consecutive: false, durationInMillis: 3000))
    }
    
    // 카메라 이동 시작이 발생하기 전에 해당 핸들러가 호출된다.
    // 파라미터로 받은 action type을 이용하여 user gesture로부터 발생한 카메라 이동은 걸러내고, move/animateCamera로 이동한 카메라 이동만 통과시킨다.
    // 즉, 패닝/탭과 같은 유저 interaction은 if문을 통과하지 않는다.
    // 한번 핸들러를 호출하고 나서는 해당 핸들러를 dispose한다.
    func cameraWillMove(_ param: CameraActionEventParam) {
        if(param.by == .notUserAction) {
            print("Camera will move")
            
            _cameraStartHandler?.dispose()
        }
    }
    
    // 카메라 이동이 멈추고나서 해당 핸들러가 호출된다.
    // 지정된 위치로 카메라 이동이 멈추면 핸들러가 호출되고, 특정 동작을 한 이후 handler를 dispose한다
    // 파라미터로 받은 camera action type을 이용하여 user gesture로부터 발생한 카메라 이동은 걸러내고, move/animateCamera로 이동한 카메라 이동만 통과시킨다.
    func onCameraStopped(_ param: CameraActionEventParam) {
        if(param.by == .notUserAction)
        {
            let mapView = param.view as! KakaoMap
            let position = mapView.getPosition(CGPoint(x: 0.5, y: 0.5))
            
            print("CurrentPosition:\(position.kakaoCoord.x), \(position.kakaoCoord.y)")
            
            // handler를 dispose한다.
            _cameraStoppedHandler?.dispose()
        }
    }
    
    var _cameraStoppedHandler: DisposableEventHandler?
    var _cameraStartHandler: DisposableEventHandler?
}

Camera Callbacks

moveCamera, animateCamera 등 카메라 이동 API에 부가적으로 callback을 추가할 수 있습니다. moveCamera, animateCamera의 동작이 끝나고나면 파라매터로 전달한 callback을 호출합니다.

view.animateCamera( cameraUpdate: CameraUpdate.make(area: rect), options: CameraAnimationOptions(autoElevation: false, consecutive: false, durationInMillis: 2000)) { () -> Void in
    // do something
}