프레임워크를 홍보하는 자리에서 열심히 파워포이트로 설명을 해보기도 하지만, 결국은 어떤 물건인지 보고 싶어하는 분들이 많습니다.
그런데 그 때마다 VS를 띄우고 예를 보여주는 것도 참 힘이 든 작업입니다. 전속 홍보 담당자가 있는 것도 아니기 때문에 여러 차선책을 강구하게 됩니다.
그 중에 동영상으로 간단히 보여주는 것이 큰 효과가 있는 것 같습니다.
PS. 업로드용으로 인코딩을 했기 때문에 화질이 좋지는 못합니다.
프레임워크를 홍보하는 자리에서 열심히 파워포이트로 설명을 해보기도 하지만, 결국은 어떤 물건인지 보고 싶어하는 분들이 많습니다.
그런데 그 때마다 VS를 띄우고 예를 보여주는 것도 참 힘이 든 작업입니다. 전속 홍보 담당자가 있는 것도 아니기 때문에 여러 차선책을 강구하게 됩니다.
그 중에 동영상으로 간단히 보여주는 것이 큰 효과가 있는 것 같습니다.
PS. 업로드용으로 인코딩을 했기 때문에 화질이 좋지는 못합니다.
MouseWheelHelper.csMouseWheelHelper
일단 위에 있는 변수들이 필요하고요. 이변수들은 마우스 드래그 시 object 이동을 구현할때 사용하는 일반적인 변수들입니다. 그냥 좀 참고 하실건 Deep Zoom에 필요로 하는 좌표는 해상도에 따른 마우스 클릭한 절대 좌표가 아닌 이를 MultiScaleImage 에서 사용하는 상대적인 0 ~ 1까지 정의된 좌표라는 것입니다. 이는 msdn을 보시면 이해 하실겁니다.
http://msdn.microsoft.com/en-us/library/cc645050(VS.95).aspx
우선 우리가 무엇을 할건지 정리 해보면
마우스 휠에 따른 줌 아웃과 인을 이미지를 드래그하여 이동하는것을 구현 할것입니다.
따라서 휠이벤트와 드래그 이벤트가 반드시 필요 할것이고 드래그 이벤트 구현을 위해서
마우스 왼쪽 버튼 Down과 Up이벤트를 구현 할것입니다.
먼저 휠 이벤트를 구현하겠습니다. 이는 위에서 말한 MouseWheelHelper.cs를 이용해야 합니다.
아래 msimgPoster는 xaml에서 생성한 MultiScaleImage개체입니다.
/// 마우스 이동 핸들러를 바로 삽입 및 설정
this.MouseMove += delegate(object sender, MouseEventArgs e)
{
///MultiScaleImage 컨트롤의 위치를 저장
lastMousePos = e.GetPosition(this.msimgPoster);
};
/// 마우스 휠 이벤트 설정(MouseWheelHelper.cs 사용: MS에서 제공한 소스로 전 한게
없슴다..ㅜㅜ)
/// MouseWheelEventArgs는 MouseWheelHelper에서 정의된 것임
new MouseWheelHelper(this).Moved += delegate(object sender,MouseWheelEventArgs e)
{
double newzoom = zoom;
if (e.Delta > 0)
newzoom /= 1.3;
else
newzoom += 1.3;
/// MultiScaleImage 컨트롤 좌표를 일반적인 좌표로 변경(0,1,2....)
Point logicalPoint = this.msimgPoster.ElementToLogicalPoint(lastMousePos);
//이미지 줌 실행
msimgPoster.ZoomAboutLogicalPoint(zoom / newzoom, logicalPoint.X, logicalPoint.Y);
zoom = newzoom;
};
주석을 보시면 대부분 이해 하실겁니다. 다만 e.GetPosition(this.msimgPoster); 라는 구문을 보시면
포지션을 구하는데 마우스 클릭한 MultiScaleImage 에서의 좌표라는겁니다.
여기서 전달인자로 어떤 개체를 주건 상관없습니다. 다만 내가 어디 좌표를 사용하겠느냐에 따라 달라 지는것입니다. 근데 아마 여기서는 MultiScaleImage 를 던져 주는게 제일 좋습니다.
위에 구문을 생성자나 Loaded이벤트에 넣어 주시면 됩니다.
그럼 나머지 이벤트를 구현하겠습니다.
private void multizoom_MouseMove(object sender, MouseEventArgs e)
{
if (duringDrag)
{
Point newPoint = lastMouseViewPort; //
Point thisMouseLogicalPos = e.GetPosition(tempZoom[index]); //마우클릭한 위치
///컨트롤 이동시 마우스 클릭한 위치를 일정하게 유지 하면서 자연스럽게 이동하기 위해
///좌표를 아래와 같이 계산해야 합니다.
newPoint.X += (lastMouseLogicalPos.X - thisMouseLogicalPos.X) / msimgPoster.ActualWidth * tempZoom[index].ViewportWidth;
newPoint.Y += (lastMouseLogicalPos.Y - thisMouseLogicalPos.Y) / msimgPoster.ActualWidth * tempZoom[index].ViewportWidth;
msimgPoster.ViewportOrigin = newPoint;
}
}
//마우스 왼쪽 버튼 다운 이벤트
private void multizoom_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
lastMouseLogicalPos = e.GetPosition(msimgPoster); ///MultiScaleImage 컨트롤의 logical 좌표를 저장
lastMouseViewPort = msimgPoster.ViewportOrigin; ///MultiScaleImage 컨트롤의 top, left 좌표 저장(이미지 이동시 사용)
duringDrag = true;
}
//마우스 왼쪽 버튼 업 이벤트
private void multizoom_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
duringDrag = false;
/// spring animation 사용(spring animation 아직 잘 파악 못함)
msimgPoster.UseSprings = true;
}
나머지 이벤트들은 간단합니다. 마우스 왼쪽 버튼을 클릭하면 클릭한 좌표를 저장하고 드래그를 하겠다고 설정합니다. 그리고 마우스 이동할때 좌표들을 계산하여 이동합니다. 끝으로 마우스 왼쪽 버튼에서 손가락을 떼면 이미지 이동을 멈춥니다.
힐 이벤트도 동작할겁니다. 맨 처음 구현하겐 휠 이벤트니까요.
아 그리고 부가적인 이벤트가 있는데요 간단합니다.
/// <summary>
/// 이미지를 불러오는것이 성공 했을 때 호출
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void multizoom_ImageOpenSucceeded(object sender, RoutedEventArgs e)
{
duringOpen = true;
}
/// <summary>
/// 모션블루 효과인거 같음
/// 컨트롤이 자동으로 지원하며 모션 블루 효과가 완료 되면 호출되는 이벤트
/// </summary>
private void multizoom_MotionFinished(object sender, RoutedEventArgs e)
{
///이미지를 성공적으로 불러 왔으면 아래와 같이
///모션블루 효과가 끝났을 때 MultiScaleImage컨트롤 기본 크기 변경
if (duringOpen)
{
duringOpen = false;
///zoom out a tap bit.
msimgPoster.ViewportOrigin = new Point(-0.1, -0.2);
msimgPoster.ViewportWidth = 1.2;
}
}
주석을 보시면 이해가 가실겁니다. 이 이벤트는 처음에 MultiScaleImage 개체의 초기 설정을 해주는 이벤트입니다.
일단 이정도면 간단한 DeepZoom은 구현이 가능할겁니다. 이를 어떻게 더 활용하는냐 정도가 문제겠죠.
참고로 첨부한 소스는 약간 다른데 멍청하게 이미지 변경을 위해서 여러개의 MultiScaleImage를 생성하고 이를 배열에 넣어 참조 하는 방식으로 해서 그렇습니다. 이는 위에 잠깐 말씀 드렸듯이 요소로 빼서 Source를 설정하면 충분히 변경 가능한데요... 그건 그냥 참고만 하시기 바랍니다.^^