Nigel Paton - 2010-09-22

Hi,

I've been looking at preventing the axis labels from jumping values when scrolling and have some changes that seem to do the job. If you are unsure what I mean by jumping values try scrolling a graph which is at a zoom level that has some axis ticks that do not have labels. As you scroll the ticks that have labels will change. For example if the ticks at values 1, 3 and 5 have labels and you scroll such that 1 is no longer visible the labels will jump to being on 2, 4 and 6. It is nicer if the labels stay on the same ticks.

Extract of code from a y-axis plotting routine (based on mpScaleY::Plot but with bits I don't need removed for speed).

        // Modified from original, bit more accurate. The + 0.5 is for pixel rounding errors
        double n = ceil( (w.GetPosY() - (double)((extend - w.GetMarginBottom()) + 0.5)/ w.GetScaleY()) / step ) * step ;
        wxCoord endPx   = w.GetScrX() - w.GetMarginRight();
        wxCoord minYpx  = w.GetMarginTop();
        wxCoord maxYpx  = w.GetScrY() - w.GetMarginBottom();
        int labelW = 0;
        // Before staring cycle, calculate label height
        int labelHeigth = 0;
        s.Printf(fmt,n);
        dc.GetTextExtent(s, &tx, &labelHeigth);
        // Calculate how often to print a tick label
        int labelNumStep = (int)ceil((labelHeigth + mpMIN_Y_AXIS_LABEL_SEPARATION)/(w.GetScaleY() * step));
        // Prevent tick label drawing until the first label index is found
        int labelStepCount = labelNumStep + 1;
        // Calculate the first point at which to display a tick label
        double labelStep = step * labelNumStep;
        double firstLabel = ceil(n / labelStep) * labelStep;
        int firstLabelIndex = (int)(((firstLabel - n) + (step / 2)) / step);
        int stepCount = 0;
        for (;n < end; n += step) 
        {
            // Check whether to trigger the first label
            if (stepCount == firstLabelIndex)
                labelStepCount = labelNumStep;
            const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
            if ((p >= minYpx) && (p <= maxYpx)) 
            {
                if (m_ticks) 
                { // Draw axis ticks
                    if (m_flags == mpALIGN_BORDER_LEFT) 
                        dc.DrawLine( orgx, p, orgx+4, p);
                    else 
                        dc.DrawLine( orgx-4, p, orgx, p); //( orgx, p, orgx+4, p);
                } 
                else 
                {
                    m_pen.SetStyle(wxDOT);
                    dc.SetPen( m_pen);
                    if (m_flags == mpALIGN_LEFT)
                        dc.DrawLine( orgx-4, p, endPx, p);
                    else if (m_flags == mpALIGN_RIGHT) 
                        dc.DrawLine( minYpx, p, orgx+4, p);
                    else 
                        dc.DrawLine( 0/*-w.GetScrX()*/, p, w.GetScrX(), p);
                    m_pen.SetStyle(wxSOLID);
                    dc.SetPen( m_pen);
                }
                // Print ticks labels
                if (labelStepCount == labelNumStep)
                {
                    s.Printf(fmt, n);
                    dc.GetTextExtent(s, &tx, &ty);
                    labelW = (labelW <= tx) ? tx : labelW;
                    if ((m_flags == mpALIGN_BORDER_LEFT) || (m_flags == mpALIGN_RIGHT))
                        dc.DrawText( s, orgx+4, p-ty/2);
                    else
                        dc.DrawText( s, orgx-4-tx, p-ty/2); 
                    labelStepCount = 1;
                }
                else
                {
                    labelStepCount++;
                }
            }
            stepCount++;
        }

Can be modified for use in other axis/scale plotting routines.

Cheers

Nigel