ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Problem with XY chart Track Cursor
Posted by davide on Jun-18-2018 20:34
Attachments:
Hi Peter,

I'm having problem with XY Chart track cursor when using Scatter Layer. Whet I need to do is to create somthing similar to the 'Crosshair with Axis Labels' example using the same architecture of the 'Track Line with Data Labels' (the TrackLineLabel function).

This is my actual code. The function is triggered when the Signal 'mouseMovePlotArea' is called:

#define RANGE_TAKE_Y_VALUE      5
#define TOLERANCE_PERCENTAGE    1.
void ChartsXY::onMouseMovePlotArea(QMouseEvent*)
{
    int mousex = m_ChartViewer->getPlotAreaMouseX();
    int mousey = m_ChartViewer->getPlotAreaMouseY();

    MultiChart *m = (MultiChart*)m_ChartViewer->getChart();

    XYChart *c = (XYChart*)m->getChart(0); //I have only one XYChart on this MultiChart
    DrawArea *d = m->initDynamicLayer();
    PlotArea *p = c->getPlotArea();
    if((mousex > p->getLeftX()) && (mousex < p->getRightX()))
    {
        d->vline(p->getTopY(), p->getBottomY(), mousex, m->dashLineColor(0xffffff, 0x0101));

        ostringstream xlabel;
        xlabel << "<*block,bgColor=000000,margin=3,edgeColor=000000*>" << c->formatValue(c->getXValue(
            mousex), "{value|P4}") << "<*/*>";
        TTFText *t = d->text(xlabel.str().c_str(), "arialbd.ttf", 8);
        t->draw(mousex, p->getBottomY() + 5, 0xffffff, Chart::Top);
        t->destroy();
    }
    if((mousey < p->getBottomY()) && (mousey > p->getTopY()))
    {
        d->hline(p->getLeftX(), p->getRightX(), mousey, m->dashLineColor(0xffffff, 0x0101));
    }

    int xValue          = c->getNearestXValue(mousex);
//I want to have some tolerance on both axis
    double maxValue     = c->xAxis()->getMaxValue();
    double minValue     = c->xAxis()->getMinValue();
    double tolerance    = (fabs(maxValue) - fabs(minValue))/100.*TOLERANCE_PERCENTAGE;
    int tolerance_y     = (p->getHeight()*TOLERANCE_PERCENTAGE)/100;
    for(int i = 0; i < c->getLayerCount(); ++i)
    {
        Layer *layer = c->getLayerByZ(i);
        int xIndex = layer->getXIndexOf(xValue, tolerance);
        if(xIndex == -1)
            break;
        int xCoor = c->getXCoor(xValue);
        for(int j = 0; j < layer->getDataSetCount(); ++j)
        {
            DataSet *dataSet = layer->getDataSetByZ(j);
            double dataPoint = dataSet->getPosition(xIndex);
            Axis *yAxis = dataSet->getUseYAxis();
            int yCoor = c->getYCoor(dataPoint, yAxis);
            if((yCoor < (mousey + tolerance_y))&&(yCoor > (mousey - tolerance_y)))
            {

            }
            else
                continue;
            int color = dataSet->getDataColor();

            if ((dataPoint != Chart::NoValue) && (color != (int)Chart::Transparent) && (yCoor >=
                p->getTopY()) && (yCoor <= p->getBottomY()))
            {
                int xPos = yAxis->getX() + ((yAxis->getAlignment() == Chart::Left) ? -4 : 4);
                d->line(xCoor + 3, yCoor + 3, xCoor - 3, yCoor - 3, color);
                d->line(xCoor - 3, yCoor + 3, xCoor + 3, yCoor - 3, color);

                ostringstream label;
                label << "<*font,bgColor=000000*> " << c->formatValue(dataSet->getValue(xIndex), "{value|P4}") << " <*font*>";
                TTFText *t = d->text(label.str().c_str(), "arialbd.ttf", 8);

                if (mousex <= (p->getLeftX() + p->getRightX()) / 2)
                {
                    t->draw(mousex + 30, yCoor/*yCoorLabel*/ + c->getAbsOffsetY(), color, Chart::Left);
                }
                else
                {
                    t->draw(mousex - 30, yCoor/*yCoorLabel*/ + c->getAbsOffsetY(), color, Chart::Right);
                }
                t->destroy();
            }
        }
    }
    m_ChartViewer->updateDisplay();
}



Now the program takes correctly the value althought the cursor is not precisely on the specific point. In this way it's easy to watch the valule fo a point using the cursor.
The problem is that it does all these things based on the X-Axis and when I have a lot of vertical points it only takes the first one it finds (Am I mistaking?).
Do you have any advice on this?
It's a bit messy but maybe with the pics you will understand better the problem.

Instead of the point it takes, it should have taken the point above that is nearest to the cursor. Hope you understand.
xychart2.PNG
xychart3.PNG

  Re: Problem with XY chart Track Cursor
Posted by Peter Kwan on Jun-19-2018 01:11
Hi davide,

If your data happened to be sorted by x value, you can easily search for the point with the nearest y value. For example:

for(int j = 0; j < layer->getDataSetCount(); ++j)
{
    DataSet *dataSet = layer->getDataSetByZ(j);

    // Search for the xIndex at the same xValue and at the nearest yValue
    double yValue = c->getYValue(mousey, dataSet->getUseYAxis());
    for (int xi = xIndex - 1; layer->getXPosition(xi) == xValue; --xi)
        if (fabs(dataSet->getPosition(xi) - yValue) < fabs(dataSet->getPosition(xIndex) - yValue))
            xIndex = xi;
    for (int xi = xIndex + 1; layer->getXPosition(xi) == xValue; ++xi)
        if (fabs(dataSet->getPosition(xi) - yValue) < fabs(dataSet->getPosition(xIndex) - yValue))
            xIndex = xi;

     // Now the xIndex is adjusted to the one with the nearest y-value, can run the remaining code
     double dataPoint = dataSet->getPosition(xIndex);
     Axis *yAxis = dataSet->getUseYAxis();
     int yCoor = c->getYCoor(dataPoint, yAxis);
     .......


Hope this can help.

Regards
Peter Kwan

  Re: Problem with XY chart Track Cursor
Posted by davide on Jun-19-2018 15:59
It works perfectly Peter! Thanks a lot for your help.

Regards,
Davide Salvetti