MS Chart Прямоугольная ширина аннотации в процентах, а не в пикселях
Почему ширина прямоугольной аннотации MS-диаграммы указывается в процентах, а не в пикселях, как в msdn? https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.annotation.width(v=vs.110).aspx
Это то, что говорит msdn. Получает или задает ширину аннотации в пикселях.
Я хотел бы установить ширину в пикселях, как это указано. Я что-то здесь упускаю?
3 ответа
Поздравляем, вы нашли ошибку в документации! Легко определить, просто перейдя по ссылке на Annotation.Height docs..
Размеры Annotation
, как и многие другие в Chart
контроль, действительно приведены в процентах. Это имеет то преимущество, что они довольно умно растут и сжимаются вместе с Chart
контролировать, как и многие другие элементы.
Так что если вы удвоите ширину графика, вы в основном удвоите пространство для показанного DataPoints
и если ваш Annotation
переместился на 1/3 ширины, прежде чем он будет делать это после изменения размера диаграммы.
Что приятно.
Но не то, что вы хотели..
Таким образом, чтобы установить размер в фиксированный размер в пикселях, вам нужно сделать это:
- Рассчитайте размер, который вы хотите в процентах и установите его
- Повторяйте каждый раз, когда вы изменяете размер диаграммы или ее макета
Настоящая проблема заключается в расчете: если вы посмотрите на Chart.ClientSize
Вы получаете размер в пикселях, и чтобы получить n пикселей, вам нужно сделать что-то вроде этого:
float WidthInPercent = 100f * n / Chart.ClientSize.width;
Это, однако, не учитывает различные элементы вашего Chart
вероятно имеет: Size
из Annotation
на самом деле не рассчитывается как прямые проценты от размера диаграммы.
Вместо этого он рассчитывается в процентах от InnerPlotPosition
из ChartArea CA
,
InnerPlotPosition
по умолчанию установлено значение Auto
так что доступ к его значениям, например, CA.InnerPlotPosition.Width
вернусь 0f
; но вы можете получить (текущие!!) значения, выполнив это:
RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
То же самое касается Size/Position
из ChartArea
сам:
RectangleF CAP = CA.Position.ToRectangleF();
Теперь вы можете объединить эти проценты с (текущим!) Chart.ClientSize
чтобы узнать, какой процент вам нужно для достижения определенного размера пикселя..
Обратите внимание, что эти значения будут меняться при изменении размера, потому что внешние дополнения, такие как Legend
а также Axis
а также Labels
и т. д. не будут изменять размеры, поэтому их относительные размеры будут увеличиваться или уменьшаться по сравнению с содержащими их элементами.
Так что вам нужно пересчитать по каждому Resize
событие, или, что еще лучше: напишите функцию, которая сделает это за вас, которую вы можете вызывать, когда это необходимо...
Результатом является Annotation
который (в значительной степени из-за округления) сохранит свой размер, независимо от того, как вы изменили размер Chart
..
Вот несколько полезных функций:
Этот возвращает текущий ClientRectangle
из ChartArea
в пикселях
RectangleF ChartAreaClientRectangle(Chart chart, ChartArea CA)
{
RectangleF CAR = CA.Position.ToRectangleF();
float pw = chart.ClientSize.Width / 100f;
float ph = chart.ClientSize.Height / 100f;
return new RectangleF(pw * CAR.X, ph * CAR.Y, pw * CAR.Width, ph * CAR.Height);
}
Этот похож и возвращает текущий ClientRectangle
из ChartArea's InnerplotPosition
в пикселях:
RectangleF InnerPlotPositionClientRectangle(Chart chart, ChartArea CA)
{
RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
RectangleF CArp = ChartAreaClientRectangle(chart, CA);
float pw = CArp.Width / 100f;
float ph = CArp.Height / 100f;
return new RectangleF(CArp.X + pw * IPP.X, CArp.Y + ph * IPP.Y,
pw * IPP.Width, ph * IPP.Height);
}
Наконец, тот, который преобразует размер в пикселях в единицу в процентах, снова действителен только в настоящее время, т. Е. До следующих изменений размера или компоновки..:
SizeF Pixels2Percent( ChartArea CA, int w, int h)
{
RectangleF IPPR = InnerPlotPositionClientRectangle(chart1, CA);
float pw = 100f * w / IPPR.Width ;
float ph = 100f * h / IPPR.Height ;
return new SizeF(pw, ph);
}
Давайте посмотрим на результат до и после некоторого изменения размера:
Как вы можете видеть, размер остается прежним.
Также обратите внимание на цветные прямоугольники, которые я рисую в Paint
событие, чтобы продемонстрировать новые функции!
Здесь Paint
событие:
private void chart1_Paint(object sender, PaintEventArgs e)
{
ChartArea CA = chart1.ChartAreas[0];
e.Graphics.DrawRectangle(Pens.Violet,
Rectangle.Round(ChartAreaClientRectangle(chart1, CA)));
e.Graphics.DrawRectangle(Pens.LimeGreen,
Rectangle.Round(InnerPlotPositionClientRectangle(chart1, CA)));
}
Здесь Resize
событие:
private void chart1_Resize(object sender, EventArgs e)
{
sizeAnn(ra, new Size(24, 36));
}
А вот функция проклейки:
void sizeAnn(RectangleAnnotation ra, Size sz)
{
ChartArea CA = chart1.ChartAreas[0];
SizeF pixelPercent = Pixels2Percent(CA, sz.Width, sz.Height);
ra.Width = pixelPercent.Width;
ra.Height = pixelPercent.Height;
}
Да, мы не можем установить его в% или px, так как значение свойства установлено в double. Во-вторых, pixle = H, умноженное на W. но вы только устанавливаете ширину графика, тогда как вы можете установить ее в пикселях? Это принципиально невозможно. Я надеюсь, вы поймете, что я имею в виду.
Я знаю, что ОП хотел установить ширину в пикселях, но в случае, если некоторые люди (например, я) не хотят устанавливать ширину ни в пикселях, ни в%, а в соответствии с фактическими значениями, просто установите:
annotation.IsSizeAlwaysRelative = False
annotation.Width = whatEverValue