масштабировать, чтобы уместить холст, масштабируя до родителя, но предоставляя масштаб с помощью scrollviewer - PullRequest
0 голосов
/ 19 декабря 2018

РЕДАКТИРОВАТЬ 1 19/12

После небольшого количества гугл-фу я чувствую себя лучше, чтобы объяснить более кратко мою проблему.Я хотел реализовать «масштабирование по размеру», когда холст, который больше, чем его родитель, отображается с подходящим масштабным коэффициентом, но предлагает пользователю возможность увеличить масштаб и увидеть изображение в полном размере (с помощью средства просмотра с прокруткой).Моя первоначальная реализация не поддерживала пропорции изображения, вместо этого она работала независимо друг от друга, а затем попыталась использовать один ползунок для управления обоими.

Я наткнулся на в этом уроке , чтобы сделатьпрокручиваемый и масштабируемый просмотрщик изображений, который предлагает "масштабирование, чтобы соответствовать".После этого я изменил свой код на следующий:

if (CanvasWidth > CanvasHeight)
{
  ScaleX = (Math.Floor(_scrollViewer.ViewportWidth + 0.5)) / ((double)CanvasWidth);
  ScaleY = ScaleX;

  if (_scrollViewer.Height < (CanvasHeight * ScaleY) )
  {
    ScaleX = ( _scrollViewer.Height) / (CanvasHeight);
    ScaleY = ScaleX;
  }
}
else
{
   ScaleX = (Math.Floor(_scrollViewer.ViewportHeight + 0.5)) / ((double)CanvasHeight);
   ScaleY = ScaleX;

   if (_scrollViewer.Width < ( CanvasWidth * ScaleX) )
   {
      ScaleX = ((double)_scrollViewer.Width) / ((double)CanvasWidth);
      ScaleY = ScaleX;
   }
 }

Это изменение, кажется, работает отлично, но мне было интересно, если бы кто-нибудь мог объяснить мне, как вычисление соотношения сторон , как это работает иправильно масштабирует изображение для родительского элемента управления?

то есть, что является значимым «внутреннего оператора if» и как это обеспечивает соответственно масштабирование X и Y.


Исходный вопрос

Я динамически генерирую контент на холсте (эффективно создавая карту изображения, где каждый дочерний элемент на холсте кликабелен), где общая ширина/ высота содержимого часто больше, чем размер его родителя.В этих ситуациях я применяю ScalerTransform , чтобы масштабировать изображение до подходящего размера, чтобы оно было полностью видимым в родительском элементе управления.

<Canvas.LayoutTransform>
 <ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource 
 TemplatedParent}}" ScaleY="{Binding ScaleY,RelativeSource={RelativeSource 
 TemplatedParent}}" />
</Canvas.LayoutTransform>

Каждый дочерний элемент в Canvas имеет константуширина / высота, что означает, что я могу вычислить желаемый размер содержимого.

Я рассчитываю начальный масштабный коэффициент X / Y, выполняя что-то вроде этого.

 ScaleX = ActualCanvasWidth / DesiredCanvasWidth;
 ScaleY = ActualCanvasHeight / DesiredCanvasHeight;

Это работает, как ожидалось, иВ результате холст хорошо вписывается в родительский контейнер.

Моя проблема в том, что я хочу дать пользователю возможность масштабировать и перемещаться по изображению.Чтобы достичь этого, я обернул Canvas внутри ScrollViewer и добавил Slider.

<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" x:Name="PART_ScrollViewer" VerticalScrollBarVisibility="Auto">
<Canvas x:Name="PART_MiniMapCanvas">
    <Canvas.LayoutTransform>
        <ScaleTransform ScaleX="{Binding ScaleX,RelativeSource={RelativeSource TemplatedParent}}"
                        ScaleY="{Binding ScaleY,RelativeSource={RelativeSource TemplatedParent}}" />
    </Canvas.LayoutTransform>
</Canvas></ScrollViewer>
<Slider TickFrequency="1" IsSnapToTickEnabled="True" Grid.Row="0" Grid.Column="0" Minimum="1" Maximum="200" Value="{Binding ScaledPercent,RelativeSource={RelativeSource TemplatedParent}}" x:Name="sliderPercent" MinWidth="100px" />

Пользовательский интерфейс использует один ползунок для управления масштабированием, и его значение привязано к свойству ScaledPercent.Начальное значение ползунка рассчитывается следующим образом:

double scaledArea = (DesiredCanvasWidth * ScaleX) * (DesiredCanvasHeight* ScaleY);
double desiredArea = DesiredCanvasWidth * DesiredCanvasHeight;
double scaledPercent = scaledArea/desiredArea; 

Насколько я понимаю, я могу выполнить этот расчет, чтобы найти процент увеличения / масштаба всего холста, а не только коэффициент масштабирования X холста./Y.

Как вы можете см. Здесь , холст и его родительский объект имеют высоту примерно 160 * 200 с желаемым размером содержимого примерно 300 * 320, что соответствует 48000/96000.вот где я получил 50%, используемый ползунком.

Если пользователь решит увеличить масштаб и изменит значение ползунка на 51, я преобразую это новое значение «масштабированный процент» в подходящий ScaleX / Yзначение для холста.Это выполняется в обратном вызове свойства зависимостей

 private static void OnScaledPercentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MiniMap map)
        {
                int newPercent = (int)e.NewValue;
                int oldPercent = (int)e.OldValue;
                int diff = newPercent - oldPercent;

                double oldWidth = map.CanvasWidth * map.ScaleX;
                double oldHeight = map.CanvasHeight * map.ScaleY;

                double scale = (diff > 0 ? (100 + diff) : (100 - Math.Abs(diff))) / 100d;

                double newHeight = scale * oldHeight;
                double newWidth = scale * oldWidth;

                map.ScaleX = newWidth / map.CanvasWidth;
                map.ScaleY = newHeight / map.CanvasHeight;
        }
    }

Как вы можете видеть, я эффективно масштабирую ширину / высоту старого изображения на +/- 1%, а затем вычисляю новые значения масштаба X / Y.Похоже, это работает, как вы можете см. Здесь , но если вы постоянно увеличиваете / уменьшаете масштаб, холст становится настолько маленьким, что не отображается.Я предполагаю, что это потому, что я вычисляю новую ширину / высоту каждый раз, и она в конечном итоге будет округляться до 0.

Очевидно, что моя реализация слишком сложна, содержит ошибки и ошибочна.Буду признателен, если кто-нибудь сможет мне помочь или посоветовать, как мне поступить с реализацией требуемой функциональности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...