매우 높은 값으로 배율을 조정 한 후 "패닝"을 허용하려는 캔버스가 있다고 가정 해보십시오.높은 비율로 WPF 캔버스를 원점을 벗어나 부드럽게 변환하지 못합니다.
좋은 예는 전체 지구의 넓이에서 수 미터 정도까지 "확대/축소"레벨로 패닝을 허용해야하는 지리적 도구입니다.
내가 50 만 개가 넘는 말로 변환하면 매우 불규칙하게 변하지 만 캔버스의 0,0 원점에서 멀리 떨어져있는 경우에만 볼 수 있습니다.
저는 캔버스의 RenderTransform을 사용하여 번역을 시도했으며 크기가 조정 된 캔버스 위에 anothercanvas를 말 그대로 옮겨 봤습니다. 나는 다른 누군가의 샘플 앱 온라인에서도 같은 문제를 겪어왔다.
다음 예제 코드는 두 개의 다른 줌 위치에서 패닝 (클릭 및 드래그)을 제공합니다. 코드를 구현하면 버튼 하나를 클릭하여 0,0으로 확대하여 멋지고 부드러운 마우스 패닝을 찾을 수 있습니다. 그런 다음 다른 버튼을 사용하여 200, 200으로 확대하고 매끄러운 패닝은 더 이상 없습니다!
왜 이것이 문제인지 또는 어떻게 해결할 수 있는지 생각해보십시오. 샘플에 대한
XAML : 샘플
<Window x:Class="TestPanZoom.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="500" Width="500" Loaded="Window_Loaded">
<Grid PreviewMouseLeftButtonDown="Grid_PreviewMouseLeftButtonDown" MouseMove="Grid_MouseMove">
<Canvas Name="canvas1"></Canvas>
<Button Height="31"
Name="button1"
Click="button1_Click"
Margin="12,12,0,0"
VerticalAlignment="Top"
HorizontalAlignment="Left" Width="270">
Zoom WAY in to 0,0 and get smooth panning
</Button>
<Button Height="31"
Name="button2"
Click="button2_Click"
Margin="12,49,0,0"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="270">
Zoom WAY in to 200, 200 -- NO smooth panning
</Button>
</Grid>
</Window>
코드 :이 캔버스 자체에 의해 발생
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TestPanZoom
{
/// <summary>
/// Interaction logic for Window1.xaml
/// Demo of an issue with translate transform when scale is very high
/// but ONLY when you are far from the canvas's 0,0 origin.
/// Why? Is their a fix?
/// </summary>
public partial class Window1 : Window
{
Point m_clickPoint;
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Add a 2x2 black ellipse centered at 0,0
Ellipse el = new Ellipse();
el.Fill = Brushes.Black;
el.Width = 2;
el.Height = 2;
el.HorizontalAlignment = HorizontalAlignment.Left;
el.VerticalAlignment = VerticalAlignment.Top;
el.Margin = new Thickness(0 - el.Width/2, 0 - el.Height/2, 0, 0);
canvas1.Children.Add(el);
// Add a 1x1 red rectangle with its top/left corner at 0,0
Rectangle r = new Rectangle();
r.Fill = Brushes.Red;
r.Width = 1;
r.Height = 1;
r.HorizontalAlignment = HorizontalAlignment.Left;
r.VerticalAlignment = VerticalAlignment.Top;
r.Margin = new Thickness(0, 0, 0, 0);
canvas1.Children.Add(r);
// Add a 2x2 purple ellipse at a point 200,200
Point otherPoint = new Point(200, 200);
el = new Ellipse();
el.Fill = Brushes.Purple;
el.Width = 2;
el.Height = 2;
el.HorizontalAlignment = HorizontalAlignment.Left;
el.VerticalAlignment = VerticalAlignment.Top;
el.Margin = new Thickness(otherPoint.X - el.Width/2, otherPoint.Y - el.Height/2, 0, 0);
canvas1.Children.Add(el);
// Add a 1x1 blue rectangle with its top/left corner at 200,200
r = new Rectangle();
r.Fill = Brushes.Blue;
r.Width = 1;
r.Height = 1;
r.HorizontalAlignment = HorizontalAlignment.Left;
r.VerticalAlignment = VerticalAlignment.Top;
r.Margin = new Thickness(otherPoint.X, otherPoint.Y, 0, 0);
canvas1.Children.Add(r);
}
private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
m_clickPoint = e.GetPosition(this);
}
// Pan with the mouse when left-mouse is down
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point mousePosition = e.GetPosition(this);
double xDiff = mousePosition.X - m_clickPoint.X;
double yDiff = mousePosition.Y - m_clickPoint.Y;
TranslateTransform tt = new TranslateTransform(xDiff, yDiff);
TransformGroup tg = new TransformGroup();
tg.Children.Add(canvas1.RenderTransform);
tg.Children.Add(tt);
canvas1.RenderTransform = tg;
m_clickPoint = e.GetPosition(this);
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
TransformGroup tg = new TransformGroup();
double scale = 1000000;
double xCenter = 0;
double yCenter = 0;
double xOffset = (canvas1.ActualHeight/2.0 - xCenter);
double yOffset = (canvas1.ActualWidth/2.0 - yCenter);
ScaleTransform st = new ScaleTransform(scale, scale);
st.CenterX = xCenter;
st.CenterY = yCenter;
TranslateTransform tt = new TranslateTransform(xOffset, yOffset);
tg.Children.Add(st);
tg.Children.Add(tt);
canvas1.RenderTransform = tg;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
TransformGroup tg = new TransformGroup();
double scale = 1000000;
double xCenter = 200;
double yCenter = 200;
double xOffset = (canvas1.ActualHeight/2.0 - xCenter);
double yOffset = (canvas1.ActualWidth/2.0 - yCenter);
ScaleTransform st = new ScaleTransform(scale, scale);
st.CenterX = xCenter;
st.CenterY = yCenter;
TranslateTransform tt = new TranslateTransform(xOffset, yOffset);
tg.Children.Add(st);
tg.Children.Add(tt);
canvas1.RenderTransform = tg;
}
}
}
답장을 보내 주셔서 감사합니다. 이 제안 된 솔루션에는 두 가지 문제점이 있습니다. 첫째, 특정 시각적 항목을 드래그하려고하지 않고 전체 캔버스를 패닝 (캔버스의 모든 비주얼을 이동)하려고합니다. 실제 예에서, 확대하면 많은 시각적 객체가있는 세부 묘사가 나타납니다. 캔버스 주위를 움직이는 것처럼 그 물체를 둘러 봐야합니다. 둘째, 200,200에서의 드래그 효과가 여전히 원활하지 않다는 것이 두려워요. 그것을 확인하십시오 - 당신은 광장을 움켜 잡을 수 있습니다, 그러나 당신은 당신의 마우스를 조금 드래그해야합니다. 그리고 그 곳으로 점프하고, 조금 더 드래그하면 다시 점프합니다. – FTLPhysicsGuy
그것은 내 랩탑에서 부드럽습니다. 속도의 악마 : 두 번째 생각에 많은 요소 (지구 전체 egzample)가있는 1mln zoom + paning 전체 캔버스는 불가능합니다. ScaleTransform은 1000 개 이상의 IMO가 될 수 없습니다. 더 많은 것은 200.200을 드래그 할 때 0.0 정사각형을 변형하고 렌더링 할 필요가 없다는 것입니다.화면에 보이는 것을 40 %, 50 %의 부드러운 패닝으로 렌더링해야하며, Certian 레벨은 확대/축소 중에 동적으로로드해야합니다. 즉, 보는 것을 렌더링하고 조금 더 렌더링하십시오. 그러한 용기를 만드는 것은 많은 일입니다. –