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

Message ListMessage List     Post MessagePost Message

  Trace Legend For Multiple Chart
Posted by Michal Neuser on Aug-23-2018 04:07
Attachments:
Hi,

I am using multichart to display two XY charts in WPF Application. I want to display the Track Line & Legend in both the charts.

I tried the sample code mentioned in 'ZoomScrollTrackWindow' class. I am getting legends and their value is getting updated but the values are getting overlaped when i move the mouse at view port control. I tried to fix it and commented the code in drawChart method but then i am getting legend value but without legend icon color.

I have attached code i am using.Also attached the error screen shot taken.

Please help me to implement trackLineLegend with multichart. I would appreciate if you share some sample code that implements track line in multichart. Thanks for your support.
ErrorTrackLegend.docx
ErrorTrackLegend.docx

209.11 Kb
    
MethodDefinition.cs
        private void trackLineLegend(XYChart c1,  int mousec1X, int chartNo)
        {
            // Clear the current dynamic layer and get the DrawArea object to draw on it.

            if (_multiChart == null)
                d1 = c1.initDynamicLayer();
            else
            { }


            // The plot area object
            PlotArea plotArea1 = c1.getPlotArea();

            // Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
            double xValue1 = c1.getNearestXValue(mousec1X);
            int xCoor1 = c1.getXCoor(xValue1);

            // Draw a vertical track line at the x-position
            d1.vline(plotArea1.getTopY(), plotArea1.getBottomY(), xCoor1, 0xaaaaaa);

            // Container to hold the legend entries
            ArrayList legendEntries = new ArrayList();

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

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

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

                    // We are only interested in visible data sets with names
                    string dataName = dataSet.getDataName();
                    if (!string.IsNullOrEmpty(dataName))
                    {
                        if (chartNo == 1)
                        {
                            TabConfig tap = APList.FirstOrDefault(p => p.APName == dataName);
                            if (tap != null && tap.IsChecked == false)
                                continue;
                        }
                        else
                        {
                            PerformancePerameter item = OTWPerformanceParameterList.FirstOrDefault(p => p.ParameterName == dataName && p.IsChecked == true);
                            if (item == null)
                                continue;      
                        }

                    }


                    int color = dataSet.getDataColor();
                    if ((!string.IsNullOrEmpty(dataName)) && (color != Chart.Transparent))
                    {
                        // Build the legend entry, consist of the legend icon, name and data value.
                        string str = dataSet.getLegendIcon();
                        double dataValue = dataSet.getValue(xIndex);
                        legendEntries.Add("<*block*>" + dataSet.getLegendIcon() + " " + dataName + " : " + ((
                            dataValue == Chart.NoValue) ? "N/A" : c1.formatValue(dataValue, "{value|P4}")) + "<*/*>");

                        // Draw a track dot for data points within the plot area
                        int yCoor = c1.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis());
                        if ((yCoor >= plotArea1.getTopY()) && (yCoor <= plotArea1.getBottomY()))
                        {
                            d1.circle(xCoor1, yCoor, 4, 4, color, color);
                        }
                    }
                }
            }

            // Create the legend by joining the legend entries
            legendEntries.Reverse();
            string legendText = "<*block,maxWidth=" + plotArea1.getWidth() + "*><*block*><*font=Arial Bold*>["
                 + c1.xAxis().getFormattedLabel(xValue1, "hh:nn:ss") + "]<*/*>   " + String.Join(
                "    ", (string[])legendEntries.ToArray(typeof(string))) + "<*/*>";

            // Display the legend on the top of the plot area
      
            TTFText t = d1.text(legendText, "Arial Bold", 10);
            int chart1Height = 0;
            if(_multiChart != null)
            chart1Height = _multiChart.getChart(0).getHeight();
            if (chartNo == 1)
            t.draw(plotArea1.getLeftX(), plotArea1.getTopY() - 3, 0x000000, Chart.BottomLeft);
            else
                t.draw(plotArea1.getLeftX(), plotArea1.getTopY() + chart1Height - 50, 0x000000, Chart.BottomLeft);
            //  t.draw(plotArea.getLeftX() + 5, plotArea.getTopY() - 3, 0x000000, Chart.BottomCenter);
        }
		
		
		private void WPFChartViewer1_MouseMovePlotArea(object sender, MouseEventArgs e)
        {
            //var viewer = sender as WPFChartViewer;
            //trackLineLegend((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
            //viewer.updateDisplay();

            WPFChartViewer viewer = (WPFChartViewer)sender;
            MultiChart m = (MultiChart)viewer.Chart;
            _multiChart.removeDynamicLayer();
            d1 = _multiChart.initDynamicLayer();

            trackLineLegend((XYChart)_multiChart.getChart(0), viewer.PlotAreaMouseX, 1);
             trackLineLegend((XYChart)_multiChart.getChart(1), viewer.PlotAreaMouseX, 2);
             viewer.updateDisplay();
        }
		
		
		//Draw Chart Method
		private void drawChart(WPFChartViewer viewer)
        {
            if(_multiChart != null)
            {
                _multiChart.removeDynamicLayer();
                _multiChart = null;
            }

            Dictionary<string, int> graphNameAndDisplayValue = new Dictionary<string, int>();

            DateTime viewPortStartDate = Chart.NTime(viewer.getValueAtViewPort("x", viewer.ViewPortLeft));
            DateTime viewPortEndDate = Chart.NTime(viewer.getValueAtViewPort("x", viewer.ViewPortLeft +
                viewer.ViewPortWidth));

            // Get the array indexes that corresponds to the visible start and end dates
            /* int startIndex = (int)Math.Floor(Chart.bSearch(timeStamps, viewPortStartDate));
             int endIndex = (int)Math.Ceiling(Chart.bSearch(timeStamps, viewPortEndDate));*/

            int startIndex = (int)Math.Floor(Chart.bSearch(_timeSpanList.ToArray(), viewPortStartDate));
            int endIndex = (int)Math.Ceiling(Chart.bSearch(_timeSpanList.ToArray(), viewPortEndDate));
            int noOfPoints = endIndex - startIndex + 1;

            // Extract the part of the data array that are visible.
            //  DateTime[] viewPortTimeStamps = (DateTime[])Chart.arraySlice(timeStamps, startIndex, noOfPoints);
            DateTime[] viewPortTimeStamps = (DateTime[])Chart.arraySlice(_timeSpanList.ToArray(), startIndex, noOfPoints);

            //
            // At this stage, we have extracted the visible data. We can use those data to plot the chart.
            //

            //================================================================================
            // Configure overall chart appearance.
            //================================================================================

            double width = mainGrid.ColumnDefinitions[1].ActualWidth;
            double height = mainGrid.RowDefinitions[0].ActualHeight + mainGrid.RowDefinitions[1].ActualHeight;

            // Create an XYChart object of size 640 x 400 pixels
            XYChart c1 = new XYChart((int)width, (int)height/2, 0xffffff, 0x000000, 1);
            XYChart c2 = new XYChart((int)width, (int)height /2, 0xffffff, 0x000000, 1);

            // XYChart c = new XYChart(, winChartViewer1.Height);

            // Set the plotarea at (55, 55) with width 80 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() - 120, c.getHeight() - 90, c.linearGradientColor(0, 55, 0,
            //    c.getHeight() - 35, 0xf0f6ff, 0xa0c0ff), -1, Chart.Transparent, 0xffffff, 0xffffff);

            c1.setPlotArea(55, 100, c1.getWidth() - 80, c1.getHeight() - 130, 0xffffff, -1, 0x6A6666, 0xD8D5D5, 0xD8D5D5);
            c2.setPlotArea(55, 100, c1.getWidth() - 80, c2.getHeight() - 130, 0xffffff, -1, 0x6A6666, 0xD8D5D5, 0xD8D5D5);

            // As the data can lie outside the plotarea in a zoomed chart, we need enable clipping.
            c1.setClipping();
            c2.setClipping();

            // Add a title to the chart using 15pt Arial Bold font
            c1.addTitle(" Moxa Radio Analyzer RSSI And Performace Logs ", "Arial Bold", 15);

            // Set legend icon style to use line style icon, sized for 10pt font
            c1.getLegend().setLineStyleKey();
            c1.getLegend().setFontSize(10);

            c2.getLegend().setLineStyleKey();
            c2.getLegend().setFontSize(10);

            // Set the x and y axis stems to transparent and the label font to 10pt Arial
            c1.xAxis().setColors(Chart.Transparent);
            c1.yAxis().setColors(Chart.Transparent);
            c1.xAxis().setLabelStyle("Arial", 10);
            c1.yAxis().setLabelStyle("Arial", 10);

            c2.xAxis().setColors(Chart.Transparent);
            c2.yAxis().setColors(Chart.Transparent);
            c2.xAxis().setLabelStyle("Arial", 10);
            c2.yAxis().setLabelStyle("Arial", 10);

           // c2.yAxis().setLinearScale(0, 50);

            // Add axis title using 10pt Arial Bold font
            c1.yAxis().setTitle("Signal Strength", "Arial Bold", 10);

            foreach (PerformancePerameter item in OTWPerformanceParameterList)
            {
                if (item.IsChecked)
                {
                    string yAxis2Title = "";
                    switch (item.ParameterName)
                    {
                        case KEY_BAND:
                            yAxis2Title = KEY_BAND;
                            break;
                        case KEY_JTR:
                            yAxis2Title = KEY_JTR;
                            break;
                        case KEY_PCTLOSS:
                            yAxis2Title = KEY_PCTLOSS;
                            break;
                        case KEY_PERPCTLOSS:
                            yAxis2Title = KEY_PERPCTLOSS;
                            break;
                    }
                    c2.yAxis().setTitle(yAxis2Title, "Arial Bold", 10);
                }
            }

            foreach (PerformancePerameter item in WTOPerformanceParameterList)
            {
                if (item.IsChecked)
                {
                    string yAxis2Title = "";
                    switch (item.ParameterName)
                    {
                        case KEY_BAND:
                            yAxis2Title = KEY_BAND;
                            break;
                        case KEY_JTR:
                            yAxis2Title = KEY_JTR;
                            break;
                        case KEY_PCTLOSS:
                            yAxis2Title = KEY_PCTLOSS;
                            break;
                        case KEY_PERPCTLOSS:
                            yAxis2Title = KEY_PERPCTLOSS;
                            break;
                    }
                    c2.yAxis().setTitle(yAxis2Title, "Arial Bold", 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 = c1.addLineLayer2();
            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();
            layer.setXData(viewPortTimeStamps);

            // Add a line layer for the lines, using a line width of 2 pixels
            LineLayer layer2 = c2.addLineLayer2();
            layer2.setLineWidth(2);
            layer2.setFastLineMode();

            bool handoffDrawn = false;
            foreach (string key in _dicTapNameAndTapMACAddress.Keys)
            {
                string graphName = key;

                string equipName = _dicTapNameAndTapMACAddress[graphName];

                if (_dicTapMacAndValues.ContainsKey(equipName))
                {
                    string dataSeriesName = graphName;

                    double[] dataSeriesValue = _dicTapMacAndValues[equipName].ToArray();
                    DateTime[] dataDateTimeForAxisY = _dicTapMacAndDateTimeValues[equipName].ToArray();
                    int countDateTimeHnadOff = dataDateTimeForAxisY.Count();

                    TabConfig tap = APList.FirstOrDefault(p => p.APName == graphName);

                    double[] viewPortDataSeries = (double[])Chart.arraySlice(dataSeriesValue, startIndex, noOfPoints);

                    LineLayer layerTest = null;
                    if (_tapMacAddressAndInfo.ContainsKey(equipName))
                        layerTest = c1.addLineLayer(dataSeriesValue, _tapMacAddressAndInfo[equipName].color, dataSeriesName);
                    else
                        layerTest = c1.addLineLayer(dataSeriesValue, _colorGenerator.NextColorInt(), dataSeriesName);
                    layerTest.setXData(dataDateTimeForAxisY);
                    layerTest.setLineWidth(2);

                    if (tap != null && tap.IsChecked == false)
                    {
                        layerTest.setLineWidth(0);
                    }
                    else if (tap != null && tap.IsChecked == true)
                    {
                        layerTest.setLineWidth(2);
                    }

                    if (handoffDrawn == false)
                    {
                        handoffDrawn = true;
                        if (_handOffEquipment.Count > 0 && _timeSpanHandOff.Count > 0)
                        {
                            int x = 0;
                            foreach (string handoff in _handOffEquipment)
                            {
                                string[] separators = { "," };
                                string[] word = handoff.Split(separators, StringSplitOptions.RemoveEmptyEntries);

                                DateTime time = _timeSpanHandOff[x];
                                DateTime[] dateTimeHandOffList2 = new DateTime[2];
                                dateTimeHandOffList2[0] = time;
                                dateTimeHandOffList2[1] = time;

                                int indexStartTabHandoff = _minValue + 10;
                                int indexEndTabHandoff = _maxValue + (-10);

                                double[] dataY0 = { indexStartTabHandoff, indexEndTabHandoff }; // Define value for plot trackinfo fix value.
                                LineLayer layerTrackInfo = c1.addLineLayer(dataY0, c1.dashLineColor(0xff3333)); // fix color 
                                layerTrackInfo.setXData(dateTimeHandOffList2);

                                layerTrackInfo.addCustomDataLabel(0, 0, " " + word[0] + " \n " + word[1] + "\n" + word[2] + "\n" + word[3], "Arial Bold");
                                layerTrackInfo.setLineWidth(2);
                                layerTrackInfo.getDataSet(0).setDataSymbol(Chart.SquareSymbol, 7);

                                x++;
                            }
                        }
                    }
                } // end if mapEquipAndValue

                //} //end if mapGrapNameAndEquip
            } // end For loop 

            /**** Case Add Mark BAr  ******/

            //if (_valueMarkLineList.Count() != 0)
            //{
            //    foreach (int n in _valueMarkLineList)
            //    {
            //        c.yAxis().addMark(n, 0x008000 + (1500 + n), " Line : " + n).setLineWidth(2);
            //    }

            //} // End if  value mark line 

            //AddTunnelStatus(c);
            //AddModemStatus(c);

            foreach (PerformancePerameter item in OTWPerformanceParameterList)
            {
                if (!item.IsChecked)
                {
                    continue;
                }
                if (!_dicPerVariableAndValueOTW.ContainsKey(item.ParameterName))
                {
                    continue;
                }
                string dataSeriesName = item.ParameterName;
                double[] dataSeriesValue = _dicPerVariableAndValueOTW[item.ParameterName].ToArray();
                DateTime[] dataDateTimeForAxisY = _dicIperVariableAndDateTimeOTW[item.ParameterName].ToArray();

                double[] viewPortDataSeries = (double[])Chart.arraySlice(dataSeriesValue, startIndex, noOfPoints);

                LineLayer layerPerformace = c2.addLineLayer(dataSeriesValue, _dicIperVariableAndColorOTW[item.ParameterName], dataSeriesName);
                layerPerformace.setXData(dataDateTimeForAxisY);
                layerPerformace.setLineWidth(2);
            }


            foreach (PerformancePerameter item in WTOPerformanceParameterList)
            {
                if (!item.IsChecked)
                {
                    continue;
                }
                if (!_dicPerVariableAndValueWTO.ContainsKey(item.ParameterName))
                {
                    continue;
                }
                string dataSeriesName = item.ParameterName;
                double[] dataSeriesValue = _dicPerVariableAndValueWTO[item.ParameterName].ToArray();
                DateTime[] dataDateTimeForAxisY = _dicIperVariableAndDateTimeWTO[item.ParameterName].ToArray();

                double[] viewPortDataSeries = (double[])Chart.arraySlice(dataSeriesValue, startIndex, noOfPoints);

                LineLayer layerPerformance = c2.addLineLayer(dataSeriesValue, _dicIperVariableAndColorWTO[item.ParameterName], dataSeriesName);
                layerPerformance.setXData(dataDateTimeForAxisY);
                layerPerformance.setLineWidth(2);
            }

            //================================================================================
            // 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());

            // For the automatic y-axis labels, set the minimum spacing to 30 pixels.
            c1.yAxis().setTickDensity(20);
            //c.yAxis2().setTickDensity(20);
            c2.yAxis().setTickDensity(20);

            c2.yAxis().setLinearScale(0, 50);
            //
            // In this demo, the time range can be from a few years to a few days. We demonstrate how to set
            // up different date/time format based on the time range.
            //

            // If all ticks are yearly aligned, then we use "yyyy" as the label format.
            c1.xAxis().setFormatCondition("align", 360 * 86400);
            c1.xAxis().setLabelFormat("{value|yyyy}");

            c2.xAxis().setFormatCondition("align", 360 * 86400);
            c2.xAxis().setLabelFormat("{value|yyyy}");


            // If all ticks are monthly aligned, then we use "mmm yyyy" in bold font as the first label of a
            // year, and "mmm" for other labels.
            c1.xAxis().setFormatCondition("align", 30 * 86400);
            c1.xAxis().setMultiFormat(Chart.StartOfYearFilter(), "<*font=bold*>{value|mmm<*br*>yyyy}",
                Chart.AllPassFilter(), "{value|mmm}");

            c2.xAxis().setFormatCondition("align", 30 * 86400);
            c2.xAxis().setMultiFormat(Chart.StartOfYearFilter(), "<*font=bold*>{value|mmm<*br*>yyyy}",
                Chart.AllPassFilter(), "{value|mmm}");

            // If all ticks are daily algined, then we use "mmm dd<*br*>yyyy" in bold font as the first
            // label of a year, and "mmm dd" in bold font as the first label of a month, and "dd" for other
            // labels.
            c1.xAxis().setFormatCondition("align", 86400);
            c1.xAxis().setMultiFormat(Chart.StartOfYearFilter(),
                "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}", Chart.StartOfMonthFilter(),
                "<*font=bold*>{value|mmm dd}");
            c1.xAxis().setMultiFormat2(Chart.AllPassFilter(), "{value|dd}");

            c1.xAxis().setFormatCondition("align", 3600);
            c1.xAxis().setLabelFormat("{value|hh:nn}");

            c1.xAxis().setFormatCondition("align", 3600);
            c1.xAxis().setLabelFormat("{value|hh:nn:ss}");


            // For all other cases (sub-daily ticks), use "hh:nn<*br*>mmm dd" for the first label of a day,
            // and "hh:nn" for other labels.
            c1.xAxis().setFormatCondition("else");
            c1.xAxis().setMultiFormat(Chart.StartOfDayFilter(), "<*font=bold*>{value|hh:nn:ss}",
                Chart.AllPassFilter(), "{value|hh:nn:ss.ff}");


            c2.xAxis().setFormatCondition("align", 86400);
            c2.xAxis().setMultiFormat(Chart.StartOfYearFilter(),
                "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}", Chart.StartOfMonthFilter(),
                "<*font=bold*>{value|mmm dd}");
            c2.xAxis().setMultiFormat2(Chart.AllPassFilter(), "{value|dd}");

            c2.xAxis().setFormatCondition("align", 3600);
            c2.xAxis().setLabelFormat("{value|hh:nn}");

            c2.xAxis().setFormatCondition("align", 3600);
            c2.xAxis().setLabelFormat("{value|hh:nn:ss}");


            // For all other cases (sub-daily ticks), use "hh:nn<*br*>mmm dd" for the first label of a day,
            // and "hh:nn" for other labels.
            c2.xAxis().setFormatCondition("else");
            c2.xAxis().setMultiFormat(Chart.StartOfDayFilter(), "<*font=bold*>{value|hh:nn:ss}",
                Chart.AllPassFilter(), "{value|hh:nn:ss.ff}");

            viewer.syncLinearAxisWithViewPort("x", c1.xAxis());
            //viewer.syncLinearAxisWithViewPort("y", c1.yAxis());

            viewer.syncLinearAxisWithViewPort("x", c2.xAxis());
            //viewer.syncLinearAxisWithViewPort("y", c2.yAxis());
            //================================================================================
            // 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(c1, (null == viewer.Chart) ? c1.getPlotArea().getRightX() :
                viewer.PlotAreaMouseX, 1);

                trackLineLegend(c2, (null == viewer.Chart) ? c2.getPlotArea().getRightX() :
               viewer.PlotAreaMouseX, 2);
            }

            _multiChart = new MultiChart((int)width, (int)height);
            _multiChart.addChart(0, 0, c1);
            _multiChart.addChart(0, c1.getHeight(), c2);
            _multiChart.setMainChart(_multiChart);
            viewer.Chart = _multiChart;
        }

  Re: Trace Legend For Multiple Chart
Posted by Peter Kwan on Aug-23-2018 18:49
Hi Michal,

Below please find an example:

https://www.chartdir.com/forum/download_thread.php?bn=chartdir_support&thread=1531918054#N1532367831

The above example is for Windows Forms, but the code for WPF is essentially the same. Basically, you can use a loop to draw the track line for each XYChart in the MultiChart:

        private void trackLineLabel(MultiChart m, int mouseX)
        {
            // Clear the current dynamic layer and get the DrawArea object to draw on it.
            DrawArea d = m.initDynamicLayer();

            // Draw the track line for the XYCharts
            for (int i = 0; i < m.getChartCount(); ++i)
                trackLineLabel(d, (XYChart)m.getChart(i), mouseX);
        }

Then in the trackLineLabel, your code needs to add the offsetX and offsetY to the coordinates so that the line and the legend will be in the correct position:

            int offsetX = c.getAbsOffsetX();
            int offsetY = c.getAbsOffsetY();

Hope this can help.

Regards
Peter Kwan