Соотношение сдерживать аспект в WindowsForms DataVisualization графике
Используя управление диаграммами из System.Windows.Forms.DataVisualization.Charting.Chart, я создаю точечную диаграмму.
Как я могу ограничить его так, чтобы масштаб оси X был таким же, как масштаб оси Y?
Просто установить сам элемент управления квадратным недостаточно, потому что он имеет внутренние поля для рисования и маркировки осей, которые не равны. Я мог бы выбрать определенный размер и настроить его, чтобы он был квадратным, но он должен быть как квадратным, так и изменяемым.Я искал повсюду. в документации и в браузере свойств, но я не могу ничего найти или придумать какие-либо способы сделать это в событии resize.
1 ответ:
Это хороший вопрос, но, к сожалению, нет такого простого решения, как блокировка двух
Давайте начнем с рассмотрения соответствующих игроков:Axesили установка одного значения..
Контроль
Chartимеет внутреннююSize, называемуюClientSize, которая являетсяChart.Sizeминус границы. Оба размера измеряются в пикселях.Внутри может быть один или несколько
ChartAreas. У каждого естьPosition, который имеет типElementPosition.Внутри каждого
ChartAreaнаходится область, которая используется для фактического рисования точек; она называетсяInnerPlotPosition.Свойство InnerPlotPosition определяет прямоугольник внутри диаграммы элемент area, используемый для построения данных; он исключает деления, метки осей и так далее.
Координаты, используемые для этого свойства (от 0,0 до 100,100), связаны с объект ChartArea, а не к вся карта целиком.
Свойство InnerPlotPosition можно использовать для выравнивания нескольких диаграмм области. Однако, если одна область диаграммы имеет деления и метки осей и другой - нет,их осевые линии не могут быть выровнены.
Таким образом,
- и
ChartArea.Position, иChartArea.InnerPlotPositionсодержат не только местоположение , но также размеробластей; все значения находятся в процентах внешней области, т. е.ChartArea.InnerPlotPositionотносительноChartArea.PositionиChartArea.Positionотносительно theChart.ClientSize. Все проценты идут от0-100.ChartAreaвключает в себяLabelsиLegends, а такжеAxesиTickMarks.. Мы хотим найти способ сделать квадратInnerPlotArea, то есть иметь одинаковую ширину и высоту в пикселях. Проценты не годятся! Давайте начнем с нескольких простых вычислений; если это те данные, которые у нас есть..:// we'll work with one ChartArea only..: ChartArea ca = chart1.ChartAreas[0]; ElementPosition cap = ca.Position; ElementPosition ipp = ca.InnerPlotPosition;.. тогда это размеры пикселей двух областей:
// chartarea pixel size: Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), (int)( cap.Height * chart1.ClientSize.Height / 100f)); // InnerPlotArea pixel size: Size IppSize = new Size((int)(ipp.Width * CaSize.Width / 100f), (int)(ipp.Height * CaSize.Height / 100f));В идеале мы хотели бы, чтобы
InnerPlotAreaчтобы быть квадратным; так как мы не можем очень хорошо позволить меньшей стороне расти (иначе диаграмма будет перерисовываться), нам нужно уменьшить большую. Таким образом, новый размер пикселяInnerPlotAreaравенint ippNewSide = Math.Min(IppSize.Width, IppSize.Height);Что дальше? Поскольку
Chart.Sizeтолько что был установлен, мы не хотим с ним связываться. Также не стоит возиться сChartArea: ему все еще нужно пространство для храненияLegendи т. д..Таким образом, мы меняем размер
InnerPlotArea..:Сначала создайте переменную уровня класса для хранения исходных значений
InnerPlotPosition:Он понадобится нам, чтобы сохранить исходные проценты, то есть маржу, чтобы использовать их при расчете новых. Когда мы адаптируем график, то текущие уже будут изменены / искажены..ElementPosition ipp0 = null;Затем мы создаем функцию, чтобы сделать квадрат
InnerPlotArea, который оборачивает все это:void makeSquare(Chart chart) { ChartArea ca = chart.ChartAreas[0]; // store the original value: if (ipp0 == null) ipp0 = ca.InnerPlotPosition; // get the current chart area : ElementPosition cap = ca.Position; // get both area sizes in pixels: Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), (int)( cap.Height * chart1.ClientSize.Height / 100f)); Size IppSize = new Size((int)(ipp0.Width * CaSize.Width / 100f), (int)(ipp0.Height * CaSize.Height / 100f)); // we need to use the smaller side: int ippNewSide = Math.Min(IppSize.Width, IppSize.Height); // calculate the scaling factors float px = ipp0.Width / IppSize.Width * ippNewSide; float py = ipp0.Height / IppSize.Height * ippNewSide; // use one or the other: if (IppSize.Width < IppSize.Height) ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, ipp0.Width, py); else ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, px, ipp0.Height); }Вы можете вызвать функцию после или во время изменения размера.
private void chart1_Resize(object sender, EventArgs e) { makeSquare(chart1); }Здесь действует функция:
Обратите внимание, как зеленыйChartAreaрезервирует достаточно места дляLabelsиLegendи как автоматическое масштабирование для осей все еще работает.. Но надписи по оси X теперь не помещаются в один ряд. Также обратите внимание, какChartArea.BackColorна самом деле - это цветInnerPlotAreaтолько!Обратите внимание, что вам, возможно, придется обновить переменную
ipp0, чтобы отразить измененные проценты, после внесения изменений в макетChartArea, таких как увеличение, перемещение или удалениеLegendsили изменение размера или углаLabelsи т. д..Конечно, вы можете изменить функцию, чтобы передать в любом другом соотношении, чтобы сохранить вместо сохранения площади участка квадрат..


