|
What's the problem? |
Posted by zhongyun_cao on Sep-21-2017 16:48 |
|
I want to create a wifi frequency spectrum window follow zoomscrolltrack demo code.And I met some questions.My programming language is C++.
|
Re: What's the problem? |
Posted by Peter Kwan on Sep-22-2017 04:30 |
|
Hi zhongyun_cao,
Is it possible to clarify what is the issue? Is it possible to provide the charting part of your code and provide some sample data that can be used to reproduce the problem? Also, can be provide an image of what you think the chart should look like?
It seems the chart you have plotted has 20000 points on the x-direction, but the chart plot area is only a few hundred pixels wide. If your data are oscillating lines, because the line segments will overlap (there are 20000 line segments but only a few hundred pixels), so the chart will look like a solid region.
Regards
Peter Kwan |
Re: What's the problem? |
Posted by zhongyun_cao on Sep-22-2017 08:07 |
|
Thanks for you response!I think I have know the reason,because I didn't pay for it.when I build project with debug have no this problem. |
Re: What's the problem? |
Posted by zhongyun_cao on Sep-22-2017 08:51 |
|
Attach is my source code. |
Re: What's the problem? |
Posted by Peter Kwan on Sep-22-2017 11:20 |
|
Hi zhongyun_cao,
Even the free trail version of ChartDirector works in "Release" mode. If the code works normally in "Debug", but not in "Release", it may be a bug in the code.
For example, if there is a variable is not initialized, in "Debug" mode, the compiler may automatically initialize the variable to a fixed value, such as 0. This is to make sure the code is deterministic so it is easy to debug. In "Release" mode, the uninitialized variable may have random values, so the code may work differently.
For some reason, I cannot see your code attachment. If you would like me to have a look at the code, would you mind to resend the code once more? (After using "Choose File", you would need to press the "Send File" button to upload the file to the forum. Also, the file should not exceed 250K bytes.)
If your file is too large or if you do not want to upload it to a publicly visible forum, you may email me at pkwan@advsofteng.net
Regards
Peter Kwan |
Re: What's the problem? |
Posted by zhongyun_cao on Sep-22-2017 23:16 |
|
hi peter!
My think refer to the above is error!My data initial is wrong,but I don't know how to do it.
////////////////////////////////////////////////////////////////////////////////////
CZoomscrolltrackDlg::CZoomscrolltrackDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CZoomscrolltrackDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CZoomscrolltrackDlg::~CZoomscrolltrackDlg()
{
delete m_ranSeries;
delete m_ChartViewer.getChart();
}
void CZoomscrolltrackDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_ChartViewer, m_ChartViewer);
}
BEGIN_MESSAGE_MAP(CZoomscrolltrackDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_PointerPB, OnPointerPB)
ON_BN_CLICKED(IDC_ZoomInPB, OnZoomInPB)
ON_BN_CLICKED(IDC_ZoomOutPB, OnZoomOutPB)
ON_WM_HSCROLL()
ON_WM_MOUSEWHEEL()
ON_CONTROL(CVN_ViewPortChanged, IDC_ChartViewer, OnViewPortChanged)
ON_CONTROL(CVN_MouseMovePlotArea, IDC_ChartViewer, OnMouseMovePlotArea)
END_MESSAGE_MAP()
BOOL CZoomscrolltrackDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
//loadButtonIcon(IDC_PointerPB, IDI_PointerPB, 100, 20);
//loadButtonIcon(IDC_ZoomInPB, IDI_ZoomInPB, 100, 20);
//loadButtonIcon(IDC_ZoomOutPB, IDI_ZoomOutPB, 100, 20);
// Load the data
loadData();
// Initialize the CChartViewer
initChartViewer(&m_ChartViewer);
// Trigger the ViewPortChanged event to draw the chart
m_ChartViewer.updateViewPort(true, true);
return TRUE;
}
void CZoomscrolltrackDlg::loadData()
{
// In this example, we just use random numbers as data.
m_ranSeries = new RanSeries(127);
double labels[20000];
for(int i=0;i<20000;i++)
labels[i]=i;
m_timeStamps=DoubleArray(labels,20000);
//m_timeStamps = m_ranSeries->getDateSeries(1827, Chart::chartTime(2007, 1, 1), 86400);
m_dataSeriesA = m_ranSeries->getSeries(20000, 150, -10, 10);
m_dataSeriesB = m_ranSeries->getSeries(20000, 200, -10, 10);
m_dataSeriesC = m_ranSeries->getSeries(20000, 250, -8, 8);
}
void CZoomscrolltrackDlg::initChartViewer(CChartViewer *viewer)
{
// Set the full x range to be the duration of the data
viewer->setFullRange("x", m_timeStamps[0], m_timeStamps[m_timeStamps.len - 1]);
// Initialize the view port to show the latest 20% of the time range
viewer->setViewPortWidth(1);
viewer->setViewPortLeft(1 - viewer->getViewPortWidth());
// Set the maximum zoom to 10 points
viewer->setZoomInWidthLimit(10.0 / m_timeStamps.len);
// Initially set the mouse to drag to scroll mode.
m_PointerPB.SetCheck(1);
viewer->setMouseUsage(Chart::MouseUsageScroll);
}
void CZoomscrolltrackDlg::updateControls(CChartViewer *viewer)
{
// In this demo, we need to update the scroll bar to reflect the view port position and
// width of the view port.
m_HScrollBar.EnableWindow(viewer->getViewPortWidth() < 1);
if (viewer->getViewPortWidth() < 1)
{
SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_ALL;
info.nMin = 0;
info.nMax = 0x1fffffff;
info.nPage = (int)ceil(viewer->getViewPortWidth() * (info.nMax - info.nMin));
info.nPos = (int)(0.5 + viewer->getViewPortLeft() * (info.nMax - info.nMin)) + info.nMin;
m_HScrollBar.SetScrollInfo(&info);
}
}
//
// Draw the chart and display it in the given viewer
//
void CZoomscrolltrackDlg::drawChart(CChartViewer *viewer)
{
// Get the start date and end date that are visible on the chart.
double viewPortStartDate = viewer->getValueAtViewPort("x", viewer->getViewPortLeft());
double viewPortEndDate = viewer->getValueAtViewPort("x", viewer->getViewPortLeft() +
viewer->getViewPortWidth());
// Get the array indexes that corresponds to the visible start and end dates
int startIndex = (int)floor(Chart::bSearch(m_timeStamps, viewPortStartDate));
int endIndex = (int)ceil(Chart::bSearch(m_timeStamps, viewPortEndDate));
int noOfPoints = endIndex - startIndex + 1;
// Extract the part of the data array that are visible.
DoubleArray viewPortTimeStamps = DoubleArray(m_timeStamps.data + startIndex, noOfPoints);
DoubleArray viewPortDataSeriesA = DoubleArray(m_dataSeriesA.data + startIndex, noOfPoints);
DoubleArray viewPortDataSeriesB = DoubleArray(m_dataSeriesB.data + startIndex, noOfPoints);
DoubleArray viewPortDataSeriesC = DoubleArray(m_dataSeriesC.data + startIndex, noOfPoints);
//
// At this stage, we have extracted the visible data. We can use those data to plot the chart.
//
///////////////////////////////////////////////////////////////////////////////////////
// Configure overall chart appearance.
///////////////////////////////////////////////////////////////////////////////////////
// Create an XYChart object of size 650 x 350 pixels, with a white (ffffff) background and grey
// (aaaaaa) border
XYChart *c = new XYChart(650, 350, 0xffffff, 0xaaaaaa);
// Set the plotarea at (55, 55) with width 90 pixels less than chart width, and height 90 pixels
// less than chart height. Use a vertical gradient from light blue (f0f6ff) to sky blue (a0c0ff)
// as background. Set border to transparent and grid lines to white (ffffff).
c->setPlotArea(55, 55, c->getWidth() - 90, c->getHeight() - 90, c->linearGradientColor(0, 55, 0,
c->getHeight() - 35, 0xf0f6ff, 0xa0c0ff), -1, Chart::Transparent, 0xffffff, 0xffffff);
// As the data can lie outside the plotarea in a zoomed chart, we need enable clipping.
c->setClipping();
// Add a title to the chart using 18 pts Times New Roman Bold Italic font
c->addTitle(" Zooming and Scrolling with Track Line (1)", "timesbi.ttf", 18);
// Set legend icon style to use line style icon, sized for 8pt font
c->getLegend()->setLineStyleKey();
c->getLegend()->setFontSize(8);
// Set the axis stem to transparent
c->xAxis()->setColors(Chart::Transparent);
c->yAxis()->setColors(Chart::Transparent);
// Add axis title using 10pts Arial Bold Italic font
c->yAxis()->setTitle("Ionic Temperature (C)", "arialbi.ttf", 10);
///////////////////////////////////////////////////////////////////////////////////////
// Add data to chart
///////////////////////////////////////////////////////////////////////////////////////
//
// In this example, we represent the data by lines. You may modify the code below to use other
// representations (areas, scatter plot, etc).
//
// Add a line layer for the lines, using a line width of 2 pixels
LineLayer *layer = c->addLineLayer();
layer->setLineWidth(2);
// In this demo, we do not have too many data points. In real code, the chart may contain a lot
// of data points when fully zoomed out - much more than the number of horizontal pixels in this
// plot area. So it is a good idea to use fast line mode.
layer->setFastLineMode();
// Now we add the 3 data series to a line layer, using the color red (ff0000), green
// (00cc00) and blue (0000ff)
layer->setXData(viewPortTimeStamps);
layer->addDataSet(viewPortDataSeriesA, 0xff3333, "Alpha");
layer->addDataSet(viewPortDataSeriesB, 0x008800, "Beta");
layer->addDataSet(viewPortDataSeriesC, 0x3333CC, "Gamma");
///////////////////////////////////////////////////////////////////////////////////////
// Configure axis scale and labelling
///////////////////////////////////////////////////////////////////////////////////////
// Set the x-axis as a date/time axis with the scale according to the view port x range.
viewer->syncDateAxisWithViewPort("x", c->xAxis());
c->xAxis()->setFormatCondition("align", 1);
c->xAxis()->setLabelFormat("{value}");
c->xAxis()->setFormatCondition("else");
c->xAxis()->setLabelFormat("{value}");
///////////////////////////////////////////////////////////////////////////////////////
// Output the chart
///////////////////////////////////////////////////////////////////////////////////////
delete viewer->getChart();
viewer->setChart(c);
}
//
// Draw the track line with legend
//
void CZoomscrolltrackDlg::trackLineLegend(XYChart *c, int mouseX)
{
// Clear the current dynamic layer and get the DrawArea object to draw on it.
DrawArea *d = c->initDynamicLayer();
// The plot area object
PlotArea *plotArea = c->getPlotArea();
// Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
double xValue = c->getNearestXValue(mouseX);
int xCoor = c->getXCoor(xValue);
// Draw a vertical track line at the x-position
d->vline(plotArea->getTopY(), plotArea->getBottomY(), xCoor, d->dashLineColor(0x000000, 0x0101));
// 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);
// We are only interested in visible data sets with names
const char *dataName = dataSet->getDataName();
int color = dataSet->getDataColor();
if (dataName && *dataName && (color != Chart::Transparent)) {
// Build the legend entry, consist of the legend icon, name and data value.
double dataValue = dataSet->getValue(xIndex);
ostringstream legendEntry;
legendEntry << "<*block*>" << dataSet->getLegendIcon() << " " << dataName << ": " <<
((dataValue == Chart::NoValue) ? "N/A" : c->formatValue(dataValue, "{value|P4}"))
<< "<*/*>";
legendEntries.push_back(legendEntry.str());
// Draw a track dot for data points within the plot area
int yCoor = c->getYCoor(dataSet->getPosition(xIndex), dataSet->getUseYAxis());
if ((yCoor >= plotArea->getTopY()) && (yCoor <= plotArea->getBottomY())) {
d->circle(xCoor, yCoor, 4, 4, color, color);
}
}
}
}
// Create the legend by joining the legend entries
ostringstream legendText;
legendText << "<*block,maxWidth=" << plotArea->getWidth() << "*><*block*><*font=arialbd.ttf*>["
<< c->xAxis()->getFormattedLabel(xValue, "P4") << "]<*/*>";
for (int i = ((int)legendEntries.size()) - 1; i >= 0; --i)
legendText << " " << legendEntries[i];
// Display the legend on the top of the plot area
TTFText *t = d->text(legendText.str().c_str(), "arial.ttf", 8);
t->draw(plotArea->getLeftX() + 5, plotArea->getTopY() - 3, 0x000000, Chart::BottomLeft);
t->destroy();
}
BOOL CZoomscrolltrackDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
// Process the mouse wheel only if the mouse is over the plot area
if (!m_ChartViewer.isMouseOnPlotArea())
return FALSE;
// We zoom in or out by 10% depending on the mouse wheel direction.
double newVpWidth = m_ChartViewer.getViewPortWidth() * (zDelta > 0 ? 0.9 : 1 / 0.9);
double newVpHeight = m_ChartViewer.getViewPortHeight() * (zDelta > 0 ? 0.9 : 1 / 0.9);
// We do not zoom beyond the zoom width or height limits.
newVpWidth = max(m_ChartViewer.getZoomInWidthLimit(), min(newVpWidth,
m_ChartViewer.getZoomOutWidthLimit()));
newVpHeight = max(m_ChartViewer.getZoomInHeightLimit(), min(newVpWidth,
m_ChartViewer.getZoomOutHeightLimit()));
if ((newVpWidth != m_ChartViewer.getViewPortWidth()) ||
(newVpHeight != m_ChartViewer.getViewPortHeight()))
{
// Set the view port position and size so that the point under the mouse remains under
// the mouse after zooming.
double deltaX = (m_ChartViewer.getPlotAreaMouseX() - m_ChartViewer.getPlotAreaLeft()) *
(m_ChartViewer.getViewPortWidth() - newVpWidth) / m_ChartViewer.getPlotAreaWidth();
m_ChartViewer.setViewPortLeft(m_ChartViewer.getViewPortLeft() + deltaX);
m_ChartViewer.setViewPortWidth(newVpWidth);
double deltaY = (m_ChartViewer.getPlotAreaMouseY() - m_ChartViewer.getPlotAreaTop()) *
(m_ChartViewer.getViewPortHeight() - newVpHeight) / m_ChartViewer.getPlotAreaHeight();
m_ChartViewer.setViewPortTop(m_ChartViewer.getViewPortTop() + deltaY);
m_ChartViewer.setViewPortHeight(newVpHeight);
m_ChartViewer.updateViewPort(true, false);
}
return TRUE;
}
//
// Draw track cursor when mouse is moving over plotarea
//
void CZoomscrolltrackDlg::OnMouseMovePlotArea()
{
// Get the focus to ensure being able to receive mouse wheel events
m_ChartViewer.SetFocus();
trackLineLegend((XYChart *)m_ChartViewer.getChart(), m_ChartViewer.getPlotAreaMouseX());
m_ChartViewer.updateDisplay();
}
void CZoomscrolltrackDlg::OnViewPortChanged()
{
// In addition to updating the chart, we may also need to update other controls that
// changes based on the view port.
//updateControls(&m_ChartViewer);
// Update the chart if necessary
if (m_ChartViewer.needUpdateChart())
drawChart(&m_ChartViewer);
// 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 (!m_ChartViewer.isInMouseMoveEvent())
{
trackLineLegend((XYChart *)m_ChartViewer.getChart(), m_ChartViewer.getPlotAreaMouseX());
m_ChartViewer.updateDisplay();
}
}
|
Re: What's the problem? |
Posted by Peter Kwan on Sep-22-2017 23:36 |
|
Hi zhongyun_cao,
The error is in the lines:
double labels[20000];
for(int i=0;i<20000;i++)
labels[i]=i;
m_timeStamps=DoubleArray(labels,20000);
The "DoubleArray" only stores the pointer to the array (the labels pointer). It does not do a deep copy of the array. In your case, the "labels" is a local variable, so the array will be destroyed after "loadData". When you use m_timeStamps in drawChart, the labels array have already been destroyed, so the m_timeStamps pointers to random values.
To solve the problem, you can use:
double *labels = new double[20000];
for(int i=0;i<20000;i++)
labels[i]=i;
m_timeStamps=DoubleArray(labels,20000);
To avoid memory leak, in the destructor of your Dialog, please remember to delete the memory:
delete[] m_timeStamps.data;
Hope this can help.
Regards
Peter Kwan |
Re: What's the problem? |
Posted by cloudy_cao on Sep-27-2017 22:54 |
|
hi peter!
Thanks for you helpThe problem of data initialization has been resolved.I still have another question.Now my x axis's ticks is not fixed,but I hope the chart can be zoomed and tracked still.What do I need to do?Which demo should I used?
The attach file is my data source. |
Re: What's the problem? |
Posted by cloudy_cao on Sep-27-2017 22:58 |
|
Sorry,missed attachment,send again.
2017-9-26 MFG Data - BMic L FR.txt |
---|
|
| |
Re: What's the problem? |
Posted by Peter Kwan on Sep-29-2017 02:39 |
|
Hi cloudy_cao,
I am not too sure what is "my x axis's ticks is not fixed" mean.
From your attachment, your x-coordinates are from 8000, 7500. 7100, .... 315, 300. In the chart you attached, the chart is symmetrical with 0 in the center. So you need to add the mirror image of the data with your own code. You data should be modified to:
-8000, -7500, -7100, .... -315, -300, 300, 315, ....., 7100. 7500. 8000
In the CZoomscrolltrackDlg (Zooming and Scrolling with Track Line) sample code, ChartDirector will automatically determine the x-axis range and the ticks (labels). As an example, when you display all the data, ChartDirector may display the labels as -8000, -6000, -4000, -2000, 0, 2000, 4000, 6000, 8000. If the user zooms in to 300 - 900, ChartDirector may display the labels 300, 400, 500, 600, 700, 800, 900.
*** NOTE: In the sample code, we use syncDateAxisWithViewPort. In your case, the x-axis is numeric. Please use syncLinearAxisWithViewPort instead.
If the above is not what you mean, would you mind to clarify how you would like the chart to look like initially and after zooming in?
Regards
Peter Kwan |
Re: What's the problem? |
Posted by zhongyun_cao on Oct-09-2017 18:58 |
|
Hi peter!
"My x axis's ticks is not fixed" this is another question.The attach file which I have been provided is the data about audio frequency response.And the frequency response curves as shown below
|
Re: What's the problem? |
Posted by Peter Kwan on Oct-10-2017 14:10 |
|
Hi zhongyun,
For the x-axis of your audio chart, it is just a standard log scale axis.
c->xAxis()->setLogScale(100, 10000, 10, Chart::LinearTick);
Hope this can help.
Regards
Peter Kwan |
Re: What's the problem? |
Posted by zhongyun_cao on Oct-09-2017 19:24 |
|
hi peter!
Thanks for you again.The wifi problem I have been solve.My chart look like this.It's not perfect,but I think the function is enough
|
|