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

Message ListMessage List     Post MessagePost Message

  OnMouseMove() draws track cursor but table disappears
Posted by Rand on Mar-23-2021 20:27
OnMouseMove() draws track cursor but table disappears

I am developing an utility to configure graphs for our organization.  This includes methods to enable/disable parts of a chart such as plot area, table, track line, etc.  Everything is working correctly except when the track line is drawn in the mouse move event then the table disappears.  I will stub out the process because it is spread across many methods.
Using wxWidgets (MFC wrapper) and wxChartDir

DrawChart() configures the chart and calls setChart().
1. Create an XYChart by calling DoConfigureChart()
2. If the plot area is enabled then configure plot area, axis, and line layer
3. If the table is enabled then configure and position the table
3a. Call DoConfigTable(XYChart*) and set member CDMLTable* m_chart_table
3b. Call DoDrawTable(XYChart*) uses m_chart_table
4. Call setChart(XYChart*)
5. Call updateViewPort(true, true)
6. At this point, chart is displayed as intended with plot area and table
7. Mouse over the chart with track line enabled, table disappears until next DrawChart() call
OnMouseMove() is below

XYChart* DoConfigureChart()
{
// Set chart size, fonts, and chart->SetClipping()
}
CDMLTable* DoConfigTable( XYChart* returned from DoConfigureChart() )
{
// This works as expected for initial table drawing
// Calls chart->addTable(args), does config, returns the pointer
}
void DoDrawTable( XYChart* chart )
{
// Center table under plot area
if( m_chart_table )
{
const auto offset_x { 0 };  // offset table to the right of Y-Axis stem
const auto offset_y { 45 }; // offset table below X-Axis label
auto table_left_x { offset_x };
auto table_top_y { offset_y };
auto* plot_area { chart->getPlotArea() };
if( plot_area )
{
table_left_x = plot_area->getLeftX() + offset_x;
table_top_y = plot_area->getTopY() + plot_area->getHeight() + offset_y;
}
else
{
// Center the table
table_left_x = static_cast<int>(
ceil( (double)( chart->getWidth() - m_chart_table->getWidth() ) / 2.0 ) );
}
m_chart_table->setPos( table_left_x, table_top_y, Chart::TopLeft );
}
}
void HLTSChartViewPort::OnMouseMovePlotArea( [[maybe_unused]] wxCommandEvent& event )
{
event.Skip(); // pass to next event handler in the chain, no difference if commented out
if( IsRunning() )
{
// track cursor follows latest data, nothing to do
return;
}
// Draw track cursor when mouse is moving over PlotArea
auto mouse_x{ m_vp_manager->getPlotAreaMouseX() };
auto chart = dynamic_cast<XYChart*>(m_vp_manager->getChart() );
if( chart )
{
DoDrawTrackLineAndStatsBoxes( mouse_x, chart );
// Uncommenting Do* below makes no difference
// DoConfigTable();
// DoDrawTable( chart );
m_vp_manager->updateDisplay();
}
}

  Re: OnMouseMove() draws track cursor but table disappears
Posted by Peter Kwan on Mar-23-2021 21:08
Hi Rand,

The track cursor typically is drawn on the DrawArea object returns from initDynamicLayer. The initDynamicLayer will clear everything on the dynamic layer. Thereafter, everything drawn will be on the dynamic layer.

Note that the DrawArea object returned from the initDynamicLayer is just for convenience. It is the same DrawArea object obtained from BaseChart::getDrawArea or BaseChart::makeChart. Everything on the chart is drawn using that DrawArea object. It is just that if the drawing occurs after initDynamicLayer, it will be on the dynamic layer.

Normally, only the track cursor is drawn after initDynamicLayer. So every time it calls initDynamicLayer, it will wipe out the previous track cursor so your code can draw an update track cursor.

For your case, is it possible the table is drawn after calling initDynamicLayer? In this case, it will be on the dynamic layer, and will be clear the next time initDynamicLayer is called (in DoDrawTrackLineAndStatsBoxes?).

In other words, is the DoDrawTrackLineAndStatsBoxes only used in OnMouseMovePlotArea, or is it also used in your chart drawing code?

For example, in our sample code "Zooming and Scrolling with Track Line (1) (MFC)", near the end of the "drawChart" method, there are the lines:

    ///////////////////////////////////////////////////////////////////////////////////////
    // Output the chart
    ///////////////////////////////////////////////////////////////////////////////////////

    // We need to update the track line too. If the mouse is moving on the chart (eg. if
    // the user drags the mouse on the chart to scroll it), the track line will be updated
    // in the MouseMovePlotArea event. Otherwise, we need to update the track line here.
    if (!viewer->isInMouseMoveEvent())
    {
        trackLineLegend(c, (0 == viewer->getChart()) ? c->getPlotArea()->getRightX() :
            viewer->getPlotAreaMouseX());
    }

    delete viewer->getChart();
    viewer->setChart(c);


So in our own sample code, we do call "trackLineLegend" in the charting code. If the table is added after that line, it will be wiped out in the next time trackLineLegend is called (which will be in OnMouseMovePlotArea). If the table is added before trackLineLegend, it will not be wiped out.


For further testing, immediately after your code that calls c->addTable, please also add a line:

    c->addText(100, 100, "ABCD 1234 ABCD 1234", "arialbd.ttf", "30");

This will draw some visible text on your chart. Please check if this text disappears like the table. This is to check if the things drawn at that stage drawn are on the dynamic layer.

Regards
Peter Kwan

  Re: OnMouseMove() draws track cursor but table disappears
Posted by Rand on Mar-23-2021 21:47
Peter Kwan wrote:

Hi Rand,

The track cursor typically is drawn on the DrawArea object returns from initDynamicLayer. The initDynamicLayer will clear everything on the dynamic layer. Thereafter, everything drawn will be on the dynamic layer.

Note that the DrawArea object returned from the initDynamicLayer is just for convenience. It is the same DrawArea object obtained from BaseChart::getDrawArea or BaseChart::makeChart. Everything on the chart is drawn using that DrawArea object. It is just that if the drawing occurs after initDynamicLayer, it will be on the dynamic layer.

Normally, only the track cursor is drawn after initDynamicLayer. So every time it calls initDynamicLayer, it will wipe out the previous track cursor so your code can draw an update track cursor.

For your case, is it possible the table is drawn after calling initDynamicLayer? In this case, it will be on the dynamic layer, and will be clear the next time initDynamicLayer is called (in DoDrawTrackLineAndStatsBoxes?).
Regards
Peter Kwan

I have similar code for drawing the track cursor at the final data point if incoming data is live or the mouse move track cursor has never been activated.  That code is also conditional on !isInMouseMoveEvent().  I extracted that code to its own method and call that after assigning the table to the chart.  All now works as intended.
Knowing that all is actually drawn on the same draw area is very helpful.

I tried table->setZOrder( Chart::ChartBackZ) right after setting the table position but that did not make any difference.  According to your explanation I expected that to move the table behind the dynamic layer.  Is Z order active layer dependent?  In other words did I just move the table to the back of the dynamic layer?

Thanks again Peter.

  Re: OnMouseMove() draws track cursor but table disappears
Posted by Peter Kwan on Mar-23-2021 23:33
Hi Rand,

May be the name "dynamic layer" is not a good description of what it actually is.

When initDynamicLayer is first called, what it actually does is to take a snapshot of the chart. It does not create another layer. The code can continue to draw on the same chart with the same DrawArea. When initDynamicLayer is called again, it rolls back to the snapshot. So anything that is not in the snapshot will be wipe out, no matter how it is drawn.

Regards
Peter Kwan