Anchura de anotación rectangular de gráfico MS en porcentaje y no en píxeles

¿Por qué el ancho de la anotación rectangular de la tabla MS está en porcentaje y no en píxeles, como dice msdn? https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.annotation.width(v=vs.110).aspx

Esto es lo que dice msdn Obtiene o establece el ancho, en píxeles, de una anotación.

Me gustaría establecer mi ancho en píxeles como dice. ¿Me estoy perdiendo de algo?

¡Felicidades, has encontrado un error en la documentación! Fácil de detectar simplemente siguiendo el enlace a la anotación . Documentos de altura.

Las dimensiones de una Annotation , como muchas otras en un control de Chart , se dan en porcentajes . Esto tiene la ventaja de que crecen y contraen con bastante inteligencia con el control Chart al igual que muchos otros elementos.

Entonces, si duplicas el ancho del gráfico, básicamente doblas el espacio para los DataPoints mostrados y si tu Annotation superó un 1/3 del ancho antes de que siga haciéndolo después de que hayas cambiado el tamaño del gráfico.

Lo cual es bueno.

Pero no es lo que querías …

Por lo tanto, para establecer el tamaño a un tamaño fijo en píxeles, debe hacer esto:

  • Calcule el tamaño que desea en porcentajes y configúrelo
  • Repita cada vez que cambie el tamaño del gráfico o su diseño

El verdadero problema es el cálculo: si miras Chart.ClientSize , obtienes el tamaño en píxeles y para obtener n píxeles necesitas hacer algo como esto:

 float WidthInPercent = 100f * n / Chart.ClientSize.width; 

Sin embargo, esto no tiene en cuenta los diversos elementos que probablemente tenga su Chart : El Size de una Annotation no se calcula realmente como porcentajes directos del tamaño del gráfico.

En cambio, se califica como porcentajes de la InnerPlotPosition de InnerPlotPosition de ChartArea CA

InnerPlotPosition está configurado de forma predeterminada en Auto para acceder a sus valores, por ejemplo, CA.InnerPlotPosition.Width devolverá 0f ; pero puede obtener los valores (¡actuales!) haciendo esto:

 RectangleF IPP = CA.InnerPlotPosition.ToRectangleF(); 

Lo mismo vale para el Size/Position de la propia ChartArea :

 RectangleF CAP = CA.Position.ToRectangleF(); 

Ahora puede combinar estos porcentajes con el Chart.ClientSize ( actual! ) Chart.ClientSize averiguar qué porcentaje necesita para alcanzar un determinado tamaño de píxel.

Tenga en cuenta que estos valores cambiarán al cambiar el tamaño porque los extras externos, como Legend y Axis and Labels etc. no cambiarán de tamaño, por lo que sus tamaños relativos crecerán o parpadearán en relación con los elementos que los contienen.

Por lo tanto , debe volver a calcular cada vez que cambie el Resize evento o, mejor aún, escriba una función para que lo haga, a la que puede llamar cuando lo necesite.

El resultado es una Annotation que (prácticamente, debido al redondeo) mantendrá su tamaño, sin importar cómo cambie el tamaño del Chart .

Aquí hay algunas funciones útiles:

Éste devuelve el ClientRectangle de ClientRectangle actual de un área de ChartArea en píxeles

 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); } 

Este es similar y devuelve el ClientRectangle de ClientRectangle actual de una ChartArea's InnerplotPosition en píxeles:

 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); } 

Por último, uno que convierte un tamaño en píxeles a uno en porcentajes, nuevamente válido solo en la actualidad, es decir, hasta los siguientes cambios de tamaño o diseño:

 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); } 

Echemos un vistazo al resultado antes y después de cambiar el tamaño:

enter image description here enter image description here

Como puede ver, el tamaño permanece igual.

¡También tenga en cuenta los rectangularjs coloreados que dibujo en el evento Paint para demostrar las nuevas funciones!

Aquí está el evento 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))); } 

Aquí está el evento de Resize :

 private void chart1_Resize(object sender, EventArgs e) { sizeAnn(ra, new Size(24, 36)); } 

Y aquí la función de dimensionamiento:

 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; } 

Sí, no podemos configurarlo en% o px ya que el valor de la propiedad se establece en el doble. En segundo lugar, pixle = H multiplicado por W. pero solo está configurando el ancho del gráfico, ¿cómo puede establecerlo en pixeles? Fundamentalmente no es posible. Espero que entiendas lo que quiero decir.