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

Message ListMessage List     Post MessagePost Message

  Track BarLayers Values
Posted by Davide on May-04-2020 18:07
Hi,

I'm working with BarLayers and what I need is to track the value of each bar. I've seen the "TrackBox" example and everything works fine also on my application. In particular this is the piece of code I adopted to track the bar values:

    // Container to hold the legend entries
    vector<string> legendEntries;

    // Iterate through all layers to build the legend array
    for(int i = 0; i < c->getLayerCount(); ++i) {
        Layer *layer = c->getLayerByZ(i);

        // The data array index of the x-value
        int xIndex = layer->getXIndexOf(xValue);

        // Iterate through all the data sets in the layer
        for(int j = 0; j < layer->getDataSetCount(); ++j) {
            DataSet *dataSet = layer->getDataSetByZ(j);

            // Build the legend entry, consist of the legend icon, the name and the data value.
            double dataValue = dataSet->getValue(xIndex);
            if ((dataValue != Chart::NoValue) && (dataSet->getDataColor() != (int)Chart::Transparent)) {
                ostringstream legendEntry;
                legendEntry << dataSet->getLegendIcon() << " " << dataSet->getDataName() << ": "
                    << c->formatValue(dataValue, "{value|P4}");
                legendEntries.push_back(legendEntry.str());
            }
        }
    }

    // Create the legend by joining the legend entries
    if (legendEntries.size() > 0) {
        ostringstream legend;
        legend << "<*block,bgColor=FFFFCC,edgeColor=000000,margin=5*><*font,underline=1*>" <<
            c->xAxis()->getFormattedLabel(xValue) << "<*/font*>";
        for (int i = ((int)legendEntries.size()) - 1; i >= 0; --i)
            legend << "<*br*>" << legendEntries[i];
        legend << "<*/*>";

        // Display the legend at the bottom-right side of the mouse cursor, and make sure the legend
        // will not go outside the chart image.
        TTFText *t = d->text(legend.str().c_str(), "arialbd.ttf", 8);
        t->draw(min(mouseX + 12, c->getWidth() - t->getWidth()), min(mouseY + 18, c->getHeight()
            - t->getHeight()), 0x000000, Chart::TopLeft);
        t->destroy();
    }


Now is there a way to only get the values of every single bar and only when the mouse is on that specific bar instead of getting all the values of the bars and also if the mouse is not on a bar?

Thanks in advance.

  Re: Track BarLayers Values
Posted by Peter Kwan on May-05-2020 03:59
Hi Davide,

Your requirement looks like standard tooltips. In the qtdemo sample code, almost all the charts have tooltips. For example, you can try the "Glass Multi-Bar Chart" example in qtdemo. When the mouse is over a bar, it will display a tooltip about the bar. The tooltip is configured using the getHTMLImageMap line in the sample code. In brief, it is like:


... create the chart as usual ...

// Display the chart
viewer->setChart(c);

// Configure tooltips for the chart
const char *imageMap = c->getHTMLImageMap("", "", "title='[{dataSetName}] {xLabel}: {value}'");
viewer->setImageMap(imageMap);

Hope this can help.

Regards
Peter Kwan

  Re: Track BarLayers Values
Posted by Davide on May-05-2020 15:37
Thank you very much, I didn't know about that property.
I've seen the BaseChart.getHTMLImageMap function documentation and I managed to modify it in the way I want the value to be displayed.

The only problem I have is that in the same chart I have both bar Layers and LineLayers, so that when the mouse is on the Line Layers the value is shown as for the Bar Layers.
I looked at the doc but I didn't found something that tells the BaseChart.getHTMLImageMap to show only the values on the Bar Layers and not the values on the Line Layers.

Is this possible? Am I missing some parameters?

Thanks again!

  Re: Track BarLayers Values
Posted by Davide on May-05-2020 15:48
Davide wrote:

Thank you very much, I didn't know about that property.
I've seen the BaseChart.getHTMLImageMap function documentation and I managed to modify it in the way I want the value to be displayed.

The only problem I have is that in the same chart I have both bar Layers and LineLayers, so that when the mouse is on the Line Layers the value is shown as for the Bar Layers.
I looked at the doc but I didn't found something that tells the BaseChart.getHTMLImageMap to show only the values on the Bar Layers and not the values on the Line Layers.

Is this possible? Am I missing some parameters?

Thanks again!


Don't worry man, I ofund what In eede looking at the Dual y Axis demo in qtdemo.
I needed:

bar->setHTMLImageMap("", "", "title='{value}'");

m_ChartViewer->setChart(c);

const char *imageMap = c->getHTMLImageMap("");
m_ChartViewer->setImageMap(imageMap);

Thanks a lot! This Chartdir Library is really well done!

  Re: Track BarLayers Values
Posted by Davide on May-05-2020 16:52
Attachments:
I'm sorry for bothering you again Peter, I have just one more question. In the image above I have one problem. The bars pointed by the arrow have a really small value, like 0.1.
It happens that when I cover them with the mouse they never show me the value of the bar. But the Third bar I have pointed with the arrow, the yellow one that goes negative, shows me the value correctly.

Another strange behaviour is that in the 7° sector, where I drawn the circle, I can't get the values, also on the light blue bar doesn't show me the value, and it should be something like 0.2, so I don't think is a matter of how small the value is.

Can it be that the Line Layers cover the Bar Layers making impossible to get the event of the mouse on the bar?

Is that's the case can I do something like telling the bar layer to be plotted on top event if it's drawn after the line layers?

Thanks Peter.
Cattura4.PNG

  Re: Track BarLayers Values
Posted by Peter Kwan on May-06-2020 00:21
Hi Davide,

I suspect the behaviour you see is due to the line layer covering the bar layer. To confirm, you can do a test to remove the line layer and check if you can obtain all the bar tooltips.

A typical line is very thin (1 pixel thin), and it is very difficult to put the mouse cursor on the line. So for tooltip purposes, ChartDirector will assume the line is very thick - the default is 10 pixels. See:

https://www.advsofteng.com/doc/cdcpp.htm#LineLayer.setImageMapWidth

There is similar consideration for bars that are very short or zero in size:

https://www.advsofteng.com/doc/cdcpp.htm#BarLayer.setMinImageMapSize.htm

In your chart, there are several lines over the short bars. As they are treated as 10 pixels thick for the purpose of tooltips, it is possible they completely block the bar under it.

To address this issue, I can think of two methods:

(a) You can consider to move back to the track cursor approach. With track cursor, the mouse does not need to be exactly over the bars or lines, so it is not affected by overlapping.

(b) If you prefer the image map method, you can add an additional transparent bar layer before adding the line layer. The transparent bar layer should use the same data as your real bar layer, except all colors are set to transparent. As it is transparent, the chart will not be changed visually, but there will be a bar image map in front of the line layer. That mean in case the bars and the lines overlap, the bar tooltip will be displayed.

Regards
Peter Kwan

  Re: Track BarLayers Values
Posted by Peter Kwan on May-06-2020 13:40
Hi Davide,

instead of (b) in my last message, I have just thought of another method that can reverse the ordering of the image map. You can build the image map layer by layer, like:

// Output chart
m_ChartViewer->setChart(c);

// Bar layer image map first, followed by line layer
std::string imageMap = barLayer->getHTMLImageMap(......);
imageMap += lineLayer->getHTMLImageMap(.......);

m_ChartViewer->setImageMap(imageMap.c_str());

Hope this can help.

Regards
Peter Kwan

  Re: Track BarLayers Values
Posted by Davide on May-06-2020 15:09
Peter Kwan wrote:

Hi Davide,

instead of (b) in my last message, I have just thought of another method that can reverse the ordering of the image map. You can build the image map layer by layer, like:

// Output chart
m_ChartViewer->setChart(c);

// Bar layer image map first, followed by line layer
std::string imageMap = barLayer->getHTMLImageMap(......);
imageMap += lineLayer->getHTMLImageMap(.......);

m_ChartViewer->setImageMap(imageMap.c_str());

Hope this can help.

Regards
Peter Kwan

This solution is perfect Peter! It works really well now.

Thank you very much!