As the title says, I am using TeeChart to draw several boxplots within one chart object. Since, the number of boxplots can be quite big, I want to be able to click on a box and have information pertaining to that series to show up as a tooltip.
I am currently trying to do this with a MarksTip but for some reason, when I try to hover over the box, MarksTip will sometimes open and then immediately close (basically being visible for a split second). I have already tried setting the hide delay but it seems to be ignoring that.
Code snippet below:
seriesIndex = 0;
foreach (var seriesData in seriesDataList)
{
var series = new Box()
series.UseCustomValues = true;
series.Box.HorizSize = 5;
series.Box.Style = PointerStyles.Rectangle;
series.MildOut.Visible = true;
series.MildOut.HorizSize = 2;
series.MildOut.VertSize = 2;
series.ExtrOut.Visible = true;
series.ExtrOut.HorizSize = 2;
series.ExtrOut.VertSize = 2;
series.LinePen.Visible = _isLineVisible;
series.Pointer.Pen.Visible = true;
series.ShowInLegend = false;
series.Add(seriesIndex, seriesData);
series.Title = "tooltip text";
var tooltip = new MarksTip(Chart.Chart)
{
Series = series,
Style = MarksStyles.SeriesTitle,
HideDelay = 31000,
};
Chart.Series.Add(series);
seriesIndex++;
}
Credit to this other question for pointing me in the right direction.
I ended up using the GetSeriesMark event to modify the text of a single chart-bound MarksTip instead of creating multiple series-bound `MarksTip
seriesIndex = 0;
Chart.Tools.Add(new MarksTip());
foreach (var seriesData in seriesDataList)
{
var series = new Box()
series.UseCustomValues = true;
//Other series appearance stuff
series.Add(seriesIndex, seriesData);
series.Title = "tooltip text";
series.GetSeriesMark += (s, args) =>
{
args.MarkText = s.Title;
};
series.Marks.Visible = false;
Chart.Series.Add(series);
seriesIndex++;
}
One note about this method. The tooltip will only appear when hovering over actual datapoints and not the whole box. Not ideal but at least I can read the tooltip now.
Related
I have a chart on my WinForm that displays an EKG signal from a vital sign monitor. The chart has a scrollbar on the X-axis that allows the user to scroll back and forth to see the signal at any point they wish. This works great. The chart gets updated in real time.
The data in the chart is displayed on form load. The problem that I have is that if the user closes and reopens the form, the scrollbar button resets itself to the far left. I want the scrollbar button to be positioned at the point in the chart that is equal to the current DateTime, but I cannot find any way to do that by looking at the chart controls. Googling has not been successful.
Here is my chart setup:
private void InitializeChartEKG() {
chartEKG.ChartAreas[0].AxisX.Title = "Time";
chartEKG.ChartAreas[0].AxisX.MajorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.MinorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.IsStartedFromZero = true;
chartEKG.ChartAreas[0].CursorX.LineColor = Color.LawnGreen;
chartEKG.ChartAreas[0].CursorY.LineColor = Color.LawnGreen;
chartEKG.ChartAreas[0].AxisX.MajorGrid.Enabled = true;
chartEKG.ChartAreas[0].AxisX.MajorGrid.Interval = 100;
chartEKG.ChartAreas[0].AxisX.IsStartedFromZero = true;
chartEKG.ChartAreas[0].AxisX.MajorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.Minimum = 0;
chartEKG.ChartAreas[0].AxisY.Maximum = 600;
chartEKG.ChartAreas[0].AxisY.Minimum = -600;
chartEKG.ChartAreas[0].AxisX.Interval = 10000;
chartEKG.ChartAreas[0].AxisY.Title = "mV";
chartEKG.Series[0].XValueType = ChartValueType.DateTime;
chartEKG.Series[0].YValueType = ChartValueType.Int32;
chartEKG.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Auto;
chartEKG.ChartAreas[0].AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Auto;
chartEKG.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss tt";
chartArea = chartEKG.ChartAreas[0];
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;
int position = 0;
int blockSize = 10000;
int size = blockSize;
chartArea.AxisX.ScaleView.Zoom(position, size);
chartArea.AxisX.ScaleView.SmallScrollSize = blockSize;
chartArea.CursorX.AutoScroll = true;
chartArea.AxisX.ScrollBar.BackColor = Color.LightGray;
chartArea.AxisX.ScrollBar.ButtonColor = Color.LightSteelBlue;
chartArea.AxisX.ScrollBar.LineColor = Color.DarkBlue;
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
CultureInfo culture = new CultureInfo("en-US");
}
In the method I call to add the points I think I can do:
chartEKG.Invoke(new Action(() => chartEKG.ChartAreas[0].AxisX.ScaleView.Position = chartEKG.ChartAreas[0].AxisX.Maximum - SomeNumber);
But I'm not sure how to calculate SomeNumber
Finally was able to locate a solution. In the method that adds the points to the chart, I modified the loop that adds the points:
foreach (string point in count) {
try {
time = time.AddMilliseconds(2);
chartEKG.Invoke(new Action(() => series1.Points.AddXY(time, Convert.ToDouble(point) * 0.61)));
}
catch (ArgumentException) { }
loopCount = loopCount + 1;
string timeFormat = "yyyyMMddHHmmssfff";
string timeNow = DateTime.Now.ToString(timeFormat);
if (time == DateTime.ParseExact(DateTime.Now.ToString(timeNow), timeFormat, CultureInfo.InvariantCulture)) {
loopToStopAt = loopCount;
}
}
Then below that foreach loop, I placed this code:
chartEKG.Invoke(new Action(() => chartEKG.ChartAreas[0].AxisX.ScaleView.Scroll(chartEKG.ChartAreas[0].AxisX.Maximum - Convert.ToDouble(loopToStopAt))));
This will programmatically drag the slider to the far right of the chart, which is exactly what I want.
I am using Line graph in my application and is working fine. I tried to draw the marker points in line graph,but the marker points are not displaying.
In line chart marker properties, I have chosen markerSize as 5,markerStyle as Circle,MarkerColor as blue.Refer my code below.
series1.Name = "Series1";
series1.IsVisibleInLegend = false;
series1.IsXValueIndexed = true;
series1.XValueType = ChartValueType.Time;
series1.YAxisType = AxisType.Primary;
series1.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(series1);
I don't see how the Markers can show up from your code.
You need to set a non-default MarkerStyle:
series1.MarkerStyle = MarkerStyle.Circle;
If you use the debugger on that line you can see how the default is None !
Of course you will want to play with all other marker relates series properties, which all inherited from the DataPointCustomProperties
You are using ChartType.Line which is fine. Note that FastLine does not display markers!
If you only want to show some Markers simply style them for each point:
S1.Points[8].MarkerStyle = MarkerStyle.Triangle;
S1.Points[8].MarkerSize = 22;
S1.Points[8].MarkerColor = Color.Red;
I suggest getting each of your points, looping through them and adding each one. I noticed you want to set a name so I just created a counter then appended an integer value to the end of 'ser', name how you please.
Dim counter as int = 0;
foreach (Series ser in chart.Series)
{
ser.Name = "ser" & counter + 1;
ser.IsVisibleInLegend = false;
ser.IsXValueIndexed = true;
ser.XValueType = ChartValueType.Time;
ser.YAxisType = AxisType.Primary;
ser.ChartType = SeriesChartType.Line;
this.chart1.Series.Add(ser);
counter += 1;
}
MigraDoc.DocumentObjectModel.Tables.Row myRow= myTable.AddRow();
//Fila Titulo
MigraDoc.DocumentObjectModel.Paragraph paraTitle= myRow[0].AddParagraph("Some text");
paraTitulo.Format.Alignment = MigraDoc.DocumentObjectModel.ParagraphAlignment.Center;
myRow.Format.Font.Size = 11;
myRow.Format.Font.Bold = true;
myRow.TopPadding = 3;
myRow.BottomPadding = 2;
myRow.Format.Borders.Bottom.Width = 2.5;
myRow.Format.Borders.Right.Visible = false;
myRow.Format.Borders.Left.Visible = false;
myRow.Format.Borders.Top.Visible = false;
myRow.Format.Borders.Color = MigraDoc.DocumentObjectModel.Colors.LightBlue;
Border shadows are not implemented in MigraDoc.
You could add a dummy column to the right and a dummy row at the bottom and use those to draw a shadow yourself. This will look good only if the table fits on a single page.
I have a charting application that has an overlay function which reassigns the 'from' chart series to the 'to' chart using this code :
chTo.Series.Add(chFrom.Series[s]); //Reassign series to new chart
chTo.Legends.Add(chFrom.Legends[s]); //Reassign legend to new chart
Works great. However, I am trying to implement tooltips for the legends and am running into an issue where only the first legend in the chart will show tooltips. When I do a hittest only the first legend is recognized. All subsequent legends, while visible on the chart, aren't 'seen' to the hittest method. I'm thinking this is why the tooltips aren't showing as there is no object to trigger the mouseover event for the tooltip.
I have been unable to find a way to 'expand' the legend area (as detected by the hittest method) to make this work.
Does anyone have any ideas? Thanks!
Responding to King King --
The original legend is created in the same method as the chart thus:
//Create the series legend
chartSel.Series[ySeries.Name].ChartArea = "ChartArea1";
chartSel.Legends.Remove(chartSel.Legends.FindByName("Legend1"));
chartSel.Legends.Add(ySeries.Name);
chartSel.Legends[0].Name = ySeries.Name;
//Format the series legend
chartSel.Legends[ySeries.Name].Docking = Docking.Right;
chartSel.Legends[ySeries.Name].DockedToChartArea = "ChartArea1";
chartSel.Legends[ySeries.Name].Alignment = StringAlignment.Near;
chartSel.Legends[ySeries.Name].IsDockedInsideChartArea = false;
chartSel.Legends[ySeries.Name].LegendStyle = LegendStyle.Table; //.Row;
chartSel.Legends[ySeries.Name].TableStyle = LegendTableStyle.Tall;
chartSel.Legends[ySeries.Name].IsEquallySpacedItems = false;
chartSel.Legends[ySeries.Name].Font = new Font("Segoe UI", 7, FontStyle.Bold);
//chartSel.Legends[ySeries.Name].TextWrapThreshold = 17; // 19;
chartSel.Legends[ySeries.Name].Position.Auto = false;
chartSel.Legends[ySeries.Name].Position.X = 80;
chartSel.Legends[ySeries.Name].Position.Y = 2;
chartSel.Legends[ySeries.Name].Position.Width = 18;
chartSel.Legends[ySeries.Name].Position.Height = 12;
//Format series data point value cell
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, ""));
chartSel.Legends[ySeries.Name].CellColumns[0].Alignment = ContentAlignment.MiddleLeft; //.TopLeft;
chartSel.Legends[ySeries.Name].CellColumns[0].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(10, 10, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[0].MinimumWidth = 500;
chartSel.Legends[ySeries.Name].CellColumns[0].MaximumWidth = 500;
chartSel.Legends[ySeries.Name].CellColumns[0].BackColor = Color.FromArgb(120, chartSel.Series[ySeries.Name].Color);
//Format legend cell spacer
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, ""));
chartSel.Legends[ySeries.Name].CellColumns[1].Alignment = ContentAlignment.TopLeft;
chartSel.Legends[ySeries.Name].CellColumns[1].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 0, 0);
chartSel.Legends[ySeries.Name].CellColumns[1].MinimumWidth = 25;
chartSel.Legends[ySeries.Name].CellColumns[1].MaximumWidth = 25;
chartSel.Legends[ySeries.Name].CellColumns[1].BackColor = Color.Black;
//Format series title cell
chartSel.Legends[ySeries.Name].CellColumns.Add(new LegendCellColumn("", LegendCellColumnType.Text, ySeries.Name));
chartSel.Legends[ySeries.Name].CellColumns[2].Alignment = ContentAlignment.MiddleLeft;
chartSel.Legends[ySeries.Name].CellColumns[2].Margins = new System.Windows.Forms.DataVisualization.Charting.Margins(0, 0, 1, 1);
chartSel.Legends[ySeries.Name].CellColumns[2].MinimumWidth = 1475; //1500;
chartSel.Legends[ySeries.Name].CellColumns[2].MaximumWidth = 1475; //1500;
chartSel.Legends[ySeries.Name].CellColumns[2].ToolTip = ySeries.Name;
After the series and legends have been reassigned (using the code in my original post) I then set the legend values based on the cursor position located by the following hittest in response to a mouse-down event:
pt = activePanel.PointToClient(Control.MousePosition);
ch = activePanel.GetChildAtPoint(pt) as Chart;
if (ch != null)
{
HitTestResult ht = ch.HitTest(e.X, e.Y, false);
if (ht.ChartElementType == ChartElementType.PlottingArea)
{
SetLegendValueText(ht, ch);
}
}
private void SetLegendValueText(HitTestResult ht, Chart ch)
{
//Get the datapoint 'x' index value
int dpIndex = 0;
if (ht != null)
{
switch (ht.ChartElementType)
{
case ChartElementType.DataPoint: //Cursor is on a series line
DataPoint dp = ht.Object as DataPoint;
if (dp != null)
{
dpIndex = ht.PointIndex;
}
break;
case ChartElementType.PlottingArea: //Cursor is somewhere in the plot area of the chart
dpIndex = (int)ht.ChartArea.CursorX.Position;
break;
}
}
//Set legend value and legend tooltip
for (int x = 0; x < ch.Legends.Count; x++) //foreach (Series s in ch.Series)
{
if (dpIndex > 0)
{
ch.Legends[x].Name = "Legend_" + x;
ch.Legends[x].CellColumns[0].Text = ch.Series[x].Points[dpIndex - 1].YValues[0].ToString();
ch.Legends[x].CellColumns[0].ToolTip = ch.Legends[x].CellColumns[0].Text;
}
}
}
So, I end up with the legends looking the way I want them, but the tooltips only show for the first legend item. I've tried to do custom items as well. With them I get the tooltips, but I lose the formatting. This has been driving me crazy for weeks (off and on) and I would really like to move on to other issues. Clearly (to me anyway), I am not doing something right simply because I don't know everything there is to know about the charts, and the MSChart Samples are of very limited benefit.
I'd be most grateful if I could be pointed in the right direction.
I've got the following UIActionSheet.
How do I add it to my top navigation bar?
Preferably as the far right button.
var sheet = new UIActionSheet ("");
sheet.AddButton ("Discard Picture");
sheet.AddButton ("Pick New Picture");
sheet.AddButton ("Cancel");
sheet.CancelButtonIndex = 2;
// Dummy buttons to preserve the space for the UIImageView
for (int i = 0; i < 4; i++) {
sheet.AddButton("");
sheet.Subviews[i+4].Alpha = 0; // And of course it's better to hide them
}
var subView = new UIImageView();
subView.ContentMode = UIViewContentMode.ScaleAspectFill;
subView.Frame = new RectangleF(23,185,275,210);
// Late Steve Jobs loved rounded corners. Let's have some respect for him
subView.Layer.CornerRadius = 10;
subView.Layer.MasksToBounds = true;
subView.Layer.BorderColor = UIColor.Black.CGColor;
sheet.AddSubview(subView);
NavigationController.Add(sheet);
You can show an ActionSheet using the ShowFrom methods.
In particular, ShowFromToolbar shows the sheet from the top toolbar button.
Here's an example which shows the sheet in different ways depending on whether you are on tablet or phone:
void ActionMenu()
{
//_actionSheet = new UIActionSheet("");
UIActionSheet actionSheet = new UIActionSheet (
"Customer Actions",
null,
"Cancel",
"Delete Customer",
new string[] {"Change Customer"});
actionSheet.Style = UIActionSheetStyle.Default;
actionSheet.Clicked += delegate(object sender, UIButtonEventArgs args) {
switch (args.ButtonIndex)
{
case 0: DeleteCustomer(); break;
case 1: ChangeCustomer(); break;
}
};
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
actionSheet.ShowFromToolbar(NavigationController.Toolbar);
else
actionSheet.ShowFrom(NavigationItem.RightBarButtonItem, true);
}
https://github.com/slodge/MvvmCross-Tutorials/blob/master/Sample%20-%20CustomerManagement/CustomerManagement/CustomerManagement.Touch/Views/CustomerView.cs#L67