|
Trouble with hotspots |
Posted by MikeP on Jun-14-2013 06:48 |
|
Hello Peter.
I'm having a problem with hotspots using QChartViewer. In my updateChart method when
I create a LineLayer I set the html image map for that layer like so (this is the only html
image map that I set):
layer->setHTMLImageMap("clickable", "", "title='date: {x|yyyy-mm-dd}\\ntime:
{x|hh:nn}\\nposition: {value}'");
I also have some transparent line layers for ensuring high/low watermarks appear on the
chart which do not have html image maps set:
c->addLineLayer(1, &watermarks[0], Chart::Transparent);
c->addLineLayer(1, &watermarks[1], Chart::Transparent);
c->addLineLayer(1, &watermarks[2], Chart::Transparent);
c->addLineLayer(1, &watermarks[3], Chart::Transparent);
The onViewportChanged slot is:
void ChartWidget::onViewPortChanged()
{
if( m_viewer->needUpdateChart() )
updateChart();
if( m_viewer->needUpdateImageMap() )
updateImageMap();
}
and updateImageMap is:
void PositionLineChart::updateImageMap()
{
if( !m_viewer->getImageMapHandler() )
m_viewer->setImageMap(m_viewer->getChart()->getHTMLImageMap(""));
}
When the chart is displayed, the cursor changes properly when over a hotspot (the hand
with a finger) and I receive the clicked signal when the hotspot is clicked. However, in
my onChartClicked slot, sometimes the value for the "path" key of the ImageMapHandler
is null and sometimes it is not. The onChartClicked method is:
void PositionLineChart::onChartClicked(QMouseEvent*)
{
ImageMapHandler* imh = m_viewer->getImageMapHandler();
if( imh )
{
const char* path = imh->getValue("path");
if( path && std::string(path) == "clickable" )
{
const char* x = imh->getValue("x");
if( x )
{
...
}
}
}
}
I don't understand why sometimes the path is populated and sometimes it is not. Does it
possibly get reset somewhere and I'm not getting a chance to repopulate it again? I see
that QChartViewer::setImageMap clears it out during QChartViewer::setChart, but then
my updateImageMap method should be called after that, which I assumed would create
the html image map using the image maps set on the layers. Is this assumption incorrect?
My understanding was that a hotspot is clickable only if it has a non-empty url, thus I
don't understand why the "path" is empty in my onChartClicked method.
Thanks. |
Re: Trouble with hotspots |
Posted by Peter Kwan on Jun-14-2013 17:25 |
|
Hi MikeP,
If a layer does not call setHTMLImageMap, it will still produce an image map using the default settings in getHTMLImageMap (which is configured to have no path in your case). So for your case, one possibility is that there are layers that do not have setHTMLImageMap.
For your case, if you would like to layer to produce no image map at all, please use setHTMLImageMap("{disable}"). For example:
c->addLineLayer(1, &watermarks[0], Chart::Transparent)->setHTMLImageMap("{disabled}");
The onChartClick occurs if the user clicks on anywhere on the chart. It does not matter if he clicks on a hot spot of not, or whether the hot spot is clickable or not. In the event handler, you can check if the ImageMapHandler is null to determine if the user has clicked on a hot spot. If the user has clicked on a hot spot, you can use the ImageMapHandler to determine the hot spot parameters. You can check the "path" parameter to determine if it is a clickable hot spot or not.
The main difference between a clickable hot spot and a non-clickable hot spot is that a clickable hot spot can trigger the clickable mouse cursor (the mouse cursor changes to hand shape).
Hope this can help.
Regards
Peter Mak |
Re: Trouble with hotspots |
Posted by MikeP on Jun-14-2013 20:03 |
|
Hi Peter.
I will try to disable the image maps on the layers I'm not interested in having them on. Thanks.
I realized after the fact that onChartClick gets called both on hotspots and non-hotspots. I do check for null ImageMapHandler in the method and for debugging purposes I tried printing out all the key/value pairs. There are instances where the ImageMapHandler is not null, but there are no key/value pairs. Is this to be expected?
As I mentioned, I see the cursor change to a clickable mouse cursor (hand shape), which I thought meant that there would exist a "path" key on the ImageMapHandler, but sometimes there are no key/value pairs on the non-null ImageMapHandler.
I will try your suggestion of using {disable} and follow-up.
Thanks.
MikeP |
Re: Trouble with hotspots |
Posted by MikeP on Jun-14-2013 23:22 |
|
Hi Peter.
Using "{disable}" on the layer image maps did not work, at least not by itself. I will leave
them in, though, as it seems good form since I don't want image maps on those layers.
For debugging purposes I decided to print out the hotspot id in my onChartClicked
method. I added the following code:
void PositionLineChart::onChartClicked(QMouseEvent*)
{
int posx = m_viewer->getChartMouseX();
int posy = m_viewer->getChartMouseY();
ImageMapHandler* imh = m_viewer->getImageMapHandler();
if( imh )
{
int hotspot = imh->getHotSpot(posx, posy);
std::cout << "hotspot: " << hotspot << std::endl;
for( int i = 0; imh->getKey(i) != 0; ++i )
{
std::cout << imh->getKey(i) << ", " << imh->getValue(i) << std::endl;
}
........
}
}
I discovered that after adding the imh->getHotSpot(posx, posy) statement, I was always
able to see key/value pairs when clicking in a hotspot. If I comment out that statement,
sometimes I get key/value pairs when clicking in a hotspot and sometimes I don't. Is
calling getHotSpot() required? I didn't see it used in qtdemo.cpp onChartClicked() and my
method is based on that.
As an example, with the statement commented out, if I click in the same hotspot at the
same location multiple times, I may get key/value pairs on the first click (seems to be
random), but never get key/value pairs on subsequent clicks (the cursor has changed
from the hand back to an arrow). With the statement included, I always get key/value
pairs. Other cases are more random; sometimes switching between different hotspots will
allow the key/value pairs to be printed, sometimes not.
I use the clicks to update the display of another chart, so I am not popping up a dialog
like qtdemo does. Also, the chart updates once per second, supports scrolling and
updates the viewport to show the most recent data if it was in that configuration when
new data arrives (ie, the graph auto-scrolls to show latest data). I mention those in case
you think any may affect the functionality.
I look forward to your reply.
MikeP |
Re: Trouble with hotspots |
Posted by Peter Kwan on Jun-15-2013 03:30 |
|
Hi MikeP,
To double check on the image map, may be you can save the image map (which is a text string) on a file, and check if all "<area>" tags contain "href='clickable'"), or you may attach the file for me to analyze.
When a chart is updated, the previous image map will be cancelled, as there should be a new image map for the new chart. However, I have just checked the QChartViewer.cpp source code and found that the mouse cursor would be not updated until the mouse moves or until the mouse button is released. So if the mouse is on the chart when the chart changes, but the change is not caused by the mouse dragging or clicking, and the mouse does not move, then after the charge, the mouse cursor may not accurately reflect the hot spots.
Another QChartViewer.cpp feature is that it will try to ensure a 10ms gap between the end of one mouse move event and the starting of another mouse move event. This is to allow other events to get processed. To do this, it may delay certain mouse move events or aggregate multiple mouse move events into one event for hot spot processing. The delay is implemented as a 1ms Qt timer.
Normally, this delay should not affect mouse clicks, as the mouse normally would stopping moving before a click, so it would not cause too much mouse move events to get generated. I theorized that in some cases (such as when the CPU is busy doing other things), the delay can become significant (as Qt may not be able to fire the timer event), and it may be possible for the click event to jump ahead of the mouse move event. So the click event can occur before ChartDirector can update the "current hot spot".
If you would like to further trouble-shoot the issue, we can trace into the QChartViewer.cpp to see how the issue occur. Otherwise, I think calling getHotSpot should be a possible work around, as there is no side effect I can think of. The getHotSpot forces ChartDirector to compute the "current hot spot", and it can work if the click event happens before the mouse move event.
Regards
Peter Kwan |
Re: Trouble with hotspots |
Posted by MikeP on Jun-15-2013 04:01 |
|
Hi Peter.
Thanks for that analysis.
I wasn't sure how to retrieve the image map from the ImageMapHandler, so instead I just
looked at the result from getHTMLImageMap() that gets set on to the ImageMapHandler,
assuming it wouldn't change. All entries in the image map contain the expected value of
href="clickable?..."
You mentioned the delayed mouse event timer. That is independent of the update interval,
correct? I have the update interval set to 0 so that the chart updates immediately during
resizing and such. Wanted to mention that in case there could be some unexpected
interaction (though I didn't come across any with a quick glance).
In my program it is possible that the chart could auto-scroll without the mouse moving.
Sometimes this results in an empty path, sometimes not. Also, there are times when the
chart is stationary and I move the mouse to a new hotspot on the other side of the chart
and the path is still empty. I have put the getHotSpot() workaround in place and that
seems to be providing the functionality I intended, so as long as you think it is safe, I'm
happy with it. However, if there is some data you'd like me to provide or some change you'd
like me to make to allow you to investigate further, please let me know.
Thanks again.
MikeP |
|