PixelPositionToValue is BUGGED for logaritmic axes (Full Version)

All Forums >> [Dundas Chart] >> [Support] >> Dundas Chart for ASP.NET



Message


caspernielsen -> PixelPositionToValue is BUGGED for logaritmic axes (5/10/2007 10:41:35 AM)


Hi

After a whole day of experimenting with the PixelPositionToValue function I have come to the conclusion that it is bugged for usage in a webapplication.

The reason is that it will now work properly until the end of the page cycle (where it cannot be used for anything).

The reason I declare it bugged is that it gives different result on different stages of the lifecycle for the same input parameters. Following is my code that will demonstrate this, although some classes are not included, but I include the code here to exemplify the situation:

In the m_Chart.PostPaint the "x" will have a correct value.
in the m_Chart.PreRender the "x" will have an incorrect value (value here looks like the value should have been, had the x-axis not been logaritmic)

This means calling the PixelPositionToValue function will only work properly in the PostPaint event handler, not before. This in effect means that we cannot use the pixel position to alter any content on our page, as it have already been streamed to the output buffer.

Resolution:
Make the PixelPositionToValue function function properly earlier in the page cycle.


 
 
protected Measurement Source
{
get

{
if (ViewState["Source"] == null)
{
Random rand = new Random();
Measurement source = new Measurement();
for(int i = 0; i < Point.Frequencies.Length; i++)
{
source.Points =
new Point();
source.Points.FrequencyType = (
FrequencyType) i;
source.Points.Intensity = rand.Next(140);
}
ViewState[
"Source"] = source;
}
return ViewState["Source"] as Measurement;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
m_Chart.Series[0].Points.DataBind(Source.Points,
"Frequency", "Intensity", null);
m_Chart.Click +=
new ImageClickEventHandler(Chart_Click);
//m_Chart.PrePaint += new PaintEventHandler(Chart_PostPaint);

m_Chart.PostPaint +=
new PaintEventHandler(Chart_PostPaint);
m_Chart.PreRender +=
new EventHandler(Chart_PreRender);
}
void Chart_PreRender(object sender, EventArgs e)
{
if (!double.IsNaN(m_X) && !double.IsNaN(m_Y))
{
double x = m_Chart.ChartAreas[0].AxisX.PixelPositionToValue(m_X);
double y = m_Chart.ChartAreas[0].AxisY.PixelPositionToValue(m_Y);
if (x > 0.0 && y > 0.0)
{
double nearestFrequency = GetNearestFrequency(m_Chart.Series[0], x, m_Chart.ChartAreas[0].AxisX.Logarithmic);
m_Label.Text =
"" + nearestFrequency;
}
}
}
void Chart_PostPaint(object sender, ChartPaintEventArgs e)
{
if (sender is ChartArea && !double.IsNaN(m_X) && !double.IsNaN(m_Y))
{
double x = m_Chart.ChartAreas[0].AxisX.PixelPositionToValue(m_X);
double y = m_Chart.ChartAreas[0].AxisY.PixelPositionToValue(m_Y);
if (x > 0.0 && y > 0.0)
{
double nearestFrequency = GetNearestFrequency(m_Chart.Series[0], x, m_Chart.ChartAreas[0].AxisX.Logarithmic);
m_Label.Text =
"" + nearestFrequency;
}
}
}
private double GetNearestFrequency(Series series, double _x, bool isLogarithmic)
{
double x = isLogarithmic ? Math.Pow(10.0, _x) : _x;
double ret = Point.Frequencies[0];
foreach(int frequency in Point.Frequencies)
{
if (Math.Abs(ret - x) > Math.Abs((double)frequency - x))
{
ret = frequency;
}
}
return ret;
}
double m_X = double.NaN;
double m_Y = double.NaN;
void Chart_Click(object sender, ImageClickEventArgs e)
{
if (e.X == 0 && e.Y == 0)
{
return;
}
HitTestResult hitTestResult = this.m_Chart.HitTest(e.X, e.Y);
m_X = (
double)e.X;
m_Y = (
double)e.Y;
}




Jamie -> RE: PixelPositionToValue is BUGGED for logaritmic axes (5/10/2007 4:58:35 PM)

Hi Casper,

I would have to disagree with you, but I can help you make the PixelPositionToValue method work earlier in the page lifecycle.

The reason this method does not work is that it requires that the Chart image be painted. Until your points are plotted and painted into an image, there is no way of knowing what axis value corresponds to a given set of pixel coordinates. During the Page_Init and Page_Load portions of the page lifecycle, changes are made to the Chart control such as points being added to series, chart areas being positioned, axis settings being customized, etc., and the Chart image should not be painted until all of this is done otherwise it is a waste of processing time.

If you want to force the Chart control to paint its image earlier than its paint events, call HitTest() on the Chart before calling PixelPositionToValue and other similar methods.

Sincerely,




caspernielsen -> RE: PixelPositionToValue is BUGGED for logaritmic axes (5/11/2007 6:47:39 AM)

Hi Jamie

Thank you for your interest, but the bug remains. The reason its unquestionably a bug is that calling the same function on the same chart at two different stages of the lifecycle yields different results. The function should be deterministic and always answer correctly, or somehow state its inability to answer correctly (by for example throwing an appropriate exception).

This said the solution you provide does not solve the issue at all, calling HitTest before PixelPositionToValue still yields incorrect results.

As I stated in the earlier mail the function returns values that ignores the logaritmic flag of the axis, when called sooner than PostPaint.

Below is my new PreRender function:


void Chart_PreRender(object sender, EventArgs e)
{
if (!double.IsNaN(m_X) && !double.IsNaN(m_Y))
{
m_Chart.HitTest((
int) m_X, (int) m_Y);
double x = m_Chart.ChartAreas[0].AxisX.PixelPositionToValue(m_X);
double y = m_Chart.ChartAreas[0].AxisY.PixelPositionToValue(m_Y);
if (x > 0.0 && y > 0.0)
{
double nearestFrequency = GetNearestFrequency(m_Chart.Series[0], x, m_Chart.ChartAreas[0].AxisX.Logarithmic);
m_Label.Text =
"" + nearestFrequency;
}
}
}




Jamie -> RE: PixelPositionToValue is BUGGED for logaritmic axes (5/11/2007 8:03:27 AM)

Casper,

In the current version, before calling HitTest() an InvalidOperationException will be thrown: "PositionToValue method can not be called prior to calculating position of all chart area elements." Also, it has been noted before that this should be more clearly noted in our documentation, and I have ensured that it this will be included the next time a revision is possible. Again, unlike a bug, this was a design decision based around the page lifecycle in that a painting of the image before all properties are set would be unnecessary processing time for almost all of our clients. A change to the code is not likely for this reason, but technical support is here to find you a workable solution, and it is possible to request a paint of the Chart image and calculating of chart area elements on demand if you need to do this.

I do apologize for missing the part that the exception mentions - calculating the position of chart area elements, since this is what we are interested in. After calling the following two methods, you will be able to use PixelPositionToValue in an earlier event (to re-iterate, an event earlier than when it was designed for.)

Chart1.HitTest(x, y);
Chart1.ChartAreas[0].ReCalc();

Sincerely,




caspernielsen -> RE: PixelPositionToValue is BUGGED for logaritmic axes (5/14/2007 4:18:10 AM)

This solved my issue. Thank you.

I sincerely suggest you alter the chart code a bit and maybe add a flag to check against whether or not the picture is painted and certain values available. And maybe also add one function to call to have it painted.

Noone, no matter how skilled they may be, would have been able to figure out the solution you have provided here from the naming of the functions and the documentation only - inside information is needed.





Jamie -> RE: PixelPositionToValue is BUGGED for logaritmic axes (5/14/2007 12:23:07 PM)

Hi Casper,

I've acknowledged that this belongs explicitly in our documentation, and I expect this will be done by the next Chart release within the next couple of months. Thank you for bringing it to our attention.

It is not relatively common to use these methods outside of the paint events that they were designed for, but as I mentioned we've introduced an exception that makes it clear when they are used before the necessary painting of the Chart image. We can also add a support site article detailing what to do to make these methods accessible early.

Sincerely,




Page: [1]