internal void UpdateSegmentDragValueToolTipLow(Point pos, ChartSegment segment, double newValue) { if (!EnableDragTooltip) { return; } if (lowTooltip == null) { lowDragInfo = new ChartDragSegmentInfo() { PostfixLabelTemplate = ActualYAxis.PostfixLabelTemplate, PrefixLabelTemplate = ActualYAxis.PostfixLabelTemplate }; lowTooltip = new ContentControl { Content = lowDragInfo }; SeriesPanel.Children.Add(lowTooltip); if (DragTooltipTemplate == null) { lowTooltip.ContentTemplate = IsActualTransposed ? ChartDictionaries.GenericCommonDictionary["SegmentDragInfoOppLeft"] as DataTemplate : ChartDictionaries.GenericCommonDictionary["SegmentDragInfoOppBottom"] as DataTemplate; } else { lowTooltip.ContentTemplate = DragTooltipTemplate; } } lowDragInfo.Segment = segment; lowDragInfo.ScreenCoordinates = pos; lowDragInfo.Brush = segment.Interior; ((ChartDragSegmentInfo)lowDragInfo).NewValue = newValue; lowDragInfo.Segment = segment; lowTooltip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); if (IsActualTransposed) { if ((pos.X + lowTooltip.DesiredSize.Width > ActualWidth)) { Canvas.SetTop(lowTooltip, ActualWidth - lowTooltip.DesiredSize.Width); Canvas.SetLeft(lowTooltip, pos.X - lowTooltip.DesiredSize.Height / 2); } else { Canvas.SetTop(lowTooltip, pos.Y - lowTooltip.DesiredSize.Height / 2); Canvas.SetLeft(lowTooltip, pos.X - lowTooltip.DesiredSize.Width); } } else { if ((pos.Y + lowTooltip.DesiredSize.Height > ActualHeight)) { Canvas.SetTop(lowTooltip, ActualHeight - lowTooltip.DesiredSize.Height); Canvas.SetLeft(lowTooltip, pos.X - lowTooltip.DesiredSize.Width / 2); } else { Canvas.SetTop(lowTooltip, pos.Y); Canvas.SetLeft(lowTooltip, pos.X - lowTooltip.DesiredSize.Width / 2); } } }
/// <summary> /// Called when Pointer pressed in Chart /// </summary> /// <param name="e"></param> protected internal override void OnPointerPressed(PointerRoutedEventArgs e) { if (ChartArea == null) { return; } FrameworkElement element = e.OriginalSource as FrameworkElement; ChartSegment segment = null; ChartArea.CurrentSelectedSeries = null; if (element != null) { if (element.Tag != null) { segment = element.Tag as ChartSegment; } } if (segment != null && segment.Series is ISegmentSelectable) { mouseUnderSegment = segment; } }
protected override void OnBindingPathChanged(DependencyPropertyChangedEventArgs args) { HighValues.Clear(); LowValues.Clear(); Segment = null; base.OnBindingPathChanged(args); }
/// <summary> /// Called when [series mouse down]. /// </summary> /// <param name="source">The source.</param> /// <param name="position">The position.</param> protected internal override void OnSeriesMouseDown(object source, Point position) { this.allowExplode = true; var element = source as FrameworkElement; this.mouseUnderSegment = element != null ? element.Tag as ChartSegment : null; base.OnSeriesMouseDown(source, position); }
/// <summary> /// Called when DataSource property changed /// </summary> /// <param name="oldValue"></param> /// <param name="newValue"></param> protected override void OnDataSourceChanged(IEnumerable oldValue, IEnumerable newValue) { YValues.Clear(); Segment = null; GeneratePoints(new string[] { YBindingPath }, YValues); isPointValidated = false; this.UpdateArea(); }
private static void BindProperties(ScatterSegment scatterSegment, ChartSegment currentSegment) { Binding binding = new Binding(); binding.Source = currentSegment; binding.Path = new PropertyPath("Interior"); BindingOperations.SetBinding(scatterSegment, ChartSegment.InteriorProperty, binding); }
/// <summary> /// Called when DataSource property changed /// </summary> /// <param name="oldValue"></param> /// <param name="newValue"></param> protected override void OnDataSourceChanged(IEnumerable oldValue, IEnumerable newValue) { base.OnDataSourceChanged(oldValue, newValue); HighValues.Clear(); LowValues.Clear(); Segment = null; GeneratePoints(new string[] { High, Low }, HighValues, LowValues); isPointValidated = false; this.UpdateArea(); }
protected internal override void OnSeriesMouseDown(object source, Point position) { if (GetAnimationIsActive()) { return; } allowExplode = true; var element = source as FrameworkElement; mouseUnderSegment = element.Tag as ChartSegment; }
internal void Dispose() { if (PropertyChanged != null) { var invocationList = PropertyChanged.GetInvocationList(); foreach (var handler in invocationList) { PropertyChanged -= handler as PropertyChangedEventHandler; } PropertyChanged = null; } segment = null; item = null; series = null; trendline = null; legend = null; XFormsLabelStyle = null; XFormsLegendItem = null; }
private static ChartSegment GetSegment(ObservableCollection <ChartSegment> segments, object item) { ChartSegment toggledSegment = null; foreach (var segment in segments) { if (segment.Item == item) { toggledSegment = segment; break; } if (segment.Series is CircularSeriesBase && !double.IsNaN(((CircularSeriesBase)segment.Series).GroupTo)) { if (((CircularSeriesBase)segment.Series).GroupedData == segment.Item) { toggledSegment = segment; } } } return(toggledSegment); }
/// <summary> /// Creates the segments of Box and Whisker Series. /// </summary> public override void CreateSegments() { ClearUnUsedSegments(this.DataCount); ClearUnUsedAdornments(this.DataCount * 5); DoubleRange sbsInfo = this.GetSideBySideInfo(this); double start = sbsInfo.Start; double end = sbsInfo.End; List <double> xValues = GetXValues(); ////UpdatePercentile(); UpdateWhiskerWidth(); if (adornmentInfo != null) { UpdateAdornmentLabelPositiion(); } outlierSegments = new List <ChartSegment>(); if (YCollection == null || YCollection.Count == 0) { return; } for (int i = 0; i < DataCount; i++) { double median, lowerQuartile, upperQuartile, minimum, maximum, x1, x2, average = 0d; List <double> outliers = new List <double>(); var ylist = YCollection[i].Where(x => !double.IsNaN(x)).ToArray(); if (ylist.Count() > 0) { Array.Sort(ylist); average = ylist.Average(); } int yCount = ylist.Length; isEvenList = yCount % 2 == 0; // Getting the required values. x1 = xValues[i] + start; x2 = xValues[i] + end; if (yCount == 0) { ////To create an empty segment for the additional space requirement in range calculation. if (i < Segments.Count) { var segment = Segments[i] as BoxAndWhiskerSegment; segment.SetData(x1, x2, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, xValues[i] + sbsInfo.Median, double.NaN); segment.Item = ActualData[i]; } else { BoxAndWhiskerSegment boxEmptySegment = new BoxAndWhiskerSegment(this); boxEmptySegment.SetData(x1, x2, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, xValues[i] + sbsInfo.Median, double.NaN); boxEmptySegment.Item = ActualData[i]; Segments.Add(boxEmptySegment); } if (AdornmentsInfo != null) { if (i < Adornments.Count / 5) { SetBoxWhiskerAdornments(sbsInfo, xValues[i], double.NaN, double.NaN, x1, double.NaN, double.NaN, double.NaN, outliers, i); } else { AddBoxWhiskerAdornments(sbsInfo, xValues[i], double.NaN, double.NaN, x1, double.NaN, double.NaN, double.NaN, outliers, i); } } continue; } if (BoxPlotMode == BoxPlotMode.Exclusive) { lowerQuartile = GetExclusiveQuartileValue(ylist, yCount, 0.25d); upperQuartile = GetExclusiveQuartileValue(ylist, yCount, 0.75d); median = GetExclusiveQuartileValue(ylist, yCount, 0.5d); } else if (BoxPlotMode == BoxPlotMode.Inclusive) { lowerQuartile = GetInclusiveQuartileValue(ylist, yCount, 0.25d); upperQuartile = GetInclusiveQuartileValue(ylist, yCount, 0.75d); median = GetInclusiveQuartileValue(ylist, yCount, 0.5d); } else { // Take the first half of the list. median = GetMedianValue(ylist); GetQuartileValues(ylist, yCount, out lowerQuartile, out upperQuartile); } GetMinMaxandOutlier(lowerQuartile, upperQuartile, ylist, out minimum, out maximum, outliers); double actualMinimum = minimum; double actualMaximum = maximum; if (outliers.Count > 0) { actualMinimum = Math.Min(outliers.Min(), actualMinimum); actualMaximum = Math.Max(outliers.Max(), actualMaximum); } ChartSegment currentSegment = null; if (i < Segments.Count) { currentSegment = Segments[i]; var segment = Segments[i] as BoxAndWhiskerSegment; segment.SetData(x1, x2, actualMinimum, minimum, lowerQuartile, median, upperQuartile, maximum, actualMaximum, xValues[i] + sbsInfo.Median, average); WhiskerWidth = whiskerWidth; segment.Item = ActualData[i]; } else { BoxAndWhiskerSegment boxSegment = new BoxAndWhiskerSegment(this); boxSegment.SetData(x1, x2, actualMinimum, minimum, lowerQuartile, median, upperQuartile, maximum, actualMaximum, xValues[i] + sbsInfo.Median, average); boxSegment.Item = ActualData[i]; boxSegment.Outliers = outliers; boxSegment.WhiskerWidth = whiskerWidth; currentSegment = boxSegment; Segments.Add(boxSegment); } if (AdornmentsInfo != null) { if (i < Adornments.Count / 5) { SetBoxWhiskerAdornments(sbsInfo, xValues[i], minimum, maximum, x1, median, lowerQuartile, upperQuartile, outliers, i); } else { AddBoxWhiskerAdornments(sbsInfo, xValues[i], minimum, maximum, x1, median, lowerQuartile, upperQuartile, outliers, i); } } if (outliers.Count > 0) { foreach (var outlier in outliers) { ScatterSegment scatterSegment = new ScatterSegment(); var position = x1 + (x2 - x1) / 2; scatterSegment.SetData(position, outlier); scatterSegment.ScatterWidth = 10; scatterSegment.ScatterHeight = 10; scatterSegment.Item = ActualData[i]; scatterSegment.Series = this; scatterSegment.CustomTemplate = OutlierTemplate; // The bindings are done with the segment not with the series. BindProperties(scatterSegment, currentSegment); outlierSegments.Add(scatterSegment); } } isEvenList = false; } foreach (ScatterSegment outlierSegment in outlierSegments) { this.Segments.Add(outlierSegment); if (AdornmentsInfo != null) { var adornment = this.CreateAdornment(this, outlierSegment.XData, outlierSegment.YData, outlierSegment.XData, outlierSegment.YData); adornment.ActualLabelPosition = topLabelPosition; adornment.Item = outlierSegment.Item; this.Adornments.Add(adornment); } } }
/// <summary> /// Called when Pointer Released in Chart /// </summary> /// <param name="e"></param> protected internal override void OnPointerReleased(PointerRoutedEventArgs e) { if (ChartArea == null) { return; } if (SelectionMode == Charts.SelectionMode.MouseClick) { FrameworkElement element = e.OriginalSource as FrameworkElement; ChartSegment segment = null; ChartArea.CurrentSelectedSeries = null; if (element != null) { if (element.Tag != null) { segment = element.Tag as ChartSegment; } } if (segment is TrendlineSegment) { return; } #if __IOS__ || __ANDROID__ var image = (element as Border)?.Child as Image; #else var image = element as Image; #endif if (image != null && image.Source is WriteableBitmap) { // Bitmap segment selection process handling. OnBitmapSeriesMouseDownSelection(element, e); } else if (segment != null && segment == mouseUnderSegment && segment.Series is ISegmentSelectable && !(segment.Item is Trendline)) { if (!segment.Series.IsSideBySide && segment.Series is CartesianSeries && !(segment.Series is ScatterSeries) && !(segment.Series is BubbleSeries)) { Point canvasPoint = e.GetCurrentPoint(segment.Series.ActualArea.GetAdorningCanvas()).Position; ChartDataPointInfo data = (segment.Series as ChartSeries).GetDataPoint(canvasPoint); OnMouseDownSelection(segment.Series, data); } else { int index = -1; if ((segment.Series.ActualXAxis is CategoryAxis) && !(segment.Series.ActualXAxis as CategoryAxis).IsIndexed && segment.Series.IsSideBySide && !(segment.Series is FinancialSeriesBase) && (!(segment.Series is RangeSeriesBase)) && !(segment.Series is WaterfallSeries)) { index = segment.Series.GroupedActualData.IndexOf(segment.Item); } else { index = segment.Series is CircularSeriesBase && !double.IsNaN(((CircularSeriesBase)segment.Series).GroupTo)? segment.Series.Segments.IndexOf(segment): segment.Series.ActualData.IndexOf(segment.Item); } OnMouseDownSelection(segment.Series, index); } } else { // Get the selected adornment index and select the adornment marker index = ChartExtensionUtils.GetAdornmentIndex(element); FrameworkElement frameworkElement = e.OriginalSource as FrameworkElement; var chartAdornmentPresenter = frameworkElement as ChartAdornmentPresenter; while (frameworkElement != null && chartAdornmentPresenter == null) { frameworkElement = VisualTreeHelper.GetParent(frameworkElement) as FrameworkElement; chartAdornmentPresenter = frameworkElement as ChartAdornmentPresenter; } if (chartAdornmentPresenter != null && chartAdornmentPresenter.Series is ISegmentSelectable) { OnMouseDownSelection(chartAdornmentPresenter.Series, index); } } if (selectedAdornmentPresenter != null) { selectedAdornmentPresenter = null; } } AdorningCanvas.ReleasePointerCapture(e.Pointer); }
protected internal override void SelectedIndexChanged(int newIndex, int oldIndex) { ChartSelectionChangedEventArgs chartSelectionChangedEventArgs; ChartSegment prevSelectedSegment = null; if (ActualArea != null && ActualArea.SelectionBehaviour != null) { // Resets the adornment selection when the mouse pointer moved away from the adornment or clicked the same adornment. if (ActualArea.SelectionBehaviour.SelectionStyle == SelectionStyle.Single) { if (SelectedSegmentsIndexes.Contains(oldIndex)) { SelectedSegmentsIndexes.Remove(oldIndex); } OnResetSegment(oldIndex); } if (prevDataPoint != null && Segments.Count > 0) { prevSelectedSegment = (from segment in Segments where segment is FastLineSegment && (segment as FastLineSegment).xChartVals.Contains(prevDataPoint.XData) select segment).FirstOrDefault() as ChartSegment; } if (newIndex >= 0 && ActualArea.GetEnableSegmentSelection()) { if (!SelectedSegmentsIndexes.Contains(newIndex)) { SelectedSegmentsIndexes.Add(newIndex); } // Selects the adornment when the mouse is over or clicked on adornments(adornment selection). if (adornmentInfo != null && adornmentInfo.HighlightOnSelection) { UpdateAdornmentSelection(newIndex); } if (ActualArea != null && Segments.Count > 0) { var selectedSegment = (from segment in Segments where segment is FastLineSegment && (segment as FastLineSegment).xChartVals.Contains(dataPoint.XData) select segment).FirstOrDefault(); if (selectedSegment != null) { chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = selectedSegment, SelectedSegments = Area.SelectedSegments, SelectedSeries = this, SelectedIndex = newIndex, PreviousSelectedIndex = oldIndex, NewPointInfo = GetDataPoint(newIndex), IsSelected = true }; chartSelectionChangedEventArgs.PreviousSelectedSeries = this.ActualArea.PreviousSelectedSeries; if (oldIndex != -1) { chartSelectionChangedEventArgs.PreviousSelectedSegment = prevSelectedSegment; chartSelectionChangedEventArgs.OldPointInfo = GetDataPoint(oldIndex); } (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); PreviousSelectedIndex = newIndex; prevDataPoint = dataPoint; } } else if (Segments.Count == 0) { triggerSelectionChangedEventOnLoad = true; } } else if (newIndex == -1) { chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = null, SelectedSegments = Area.SelectedSegments, SelectedSeries = null, SelectedIndex = newIndex, PreviousSelectedIndex = oldIndex, NewPointInfo = null, OldPointInfo = GetDataPoint(oldIndex), PreviousSelectedSeries = this, IsSelected = false }; if (oldIndex != -1) { chartSelectionChangedEventArgs.PreviousSelectedSegment = prevSelectedSegment; } (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); PreviousSelectedIndex = newIndex; } } else if (newIndex >= 0 && Segments.Count == 0) { triggerSelectionChangedEventOnLoad = true; } }
/// <summary> /// Updates the chart on segment collection changed. /// </summary> /// <param name="sender">The Sender Object</param> /// <param name="e">The Collection Changed Event Arguments</param> private void OnSegmentsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { ChartSegment segment = e.NewItems[0] as ChartSegment; if (!segment.IsAddedToVisualTree) { UIElement element = segment.CreateSegmentVisual(Size.Empty); if (element != null) { var doughnutSeries = Series as DoughnutSeries; if (doughnutSeries != null) { doughnutSeries.ManipulateAdditionalVisual(element, e.Action); } Children.Add(element); segment.IsAddedToVisualTree = true; } } } else if (e.Action == NotifyCollectionChangedAction.Remove) { ChartSegment segment = e.OldItems[0] as ChartSegment; if (segment.IsAddedToVisualTree) { UIElement element = segment.GetRenderedVisual(); if (element != null && Children.Contains(element)) { var doughnutSeries = Series as DoughnutSeries; if (doughnutSeries != null) { doughnutSeries.ManipulateAdditionalVisual(element, e.Action); } Children.Remove(element); segment.IsAddedToVisualTree = false; } } } else if (e.Action == NotifyCollectionChangedAction.Reset) { for (int i = Children.Count - 1; i > -1; i--) { if (!(Children[i] is TrendlineBase)) { Children.RemoveAt(i); } } } else if (e.Action == NotifyCollectionChangedAction.Replace) { ChartSegment segment = e.NewItems[0] as ChartSegment; if (!segment.IsAddedToVisualTree) { UIElement element = segment.CreateSegmentVisual(Size.Empty); var doughnutSeries = Series as DoughnutSeries; if (doughnutSeries != null) { doughnutSeries.ManipulateAdditionalVisual(element, e.Action); } Children.Add(element); segment.IsAddedToVisualTree = true; } foreach (ChartSegment item in e.OldItems) { var element = item.GetRenderedVisual(); if (Children.Contains(element)) { Children.Remove(element); } item.IsAddedToVisualTree = false; } } }
/// <summary> /// Creates the segments of FastStackingColumnBitmapSeries /// </summary> public override void CreateSegments() { var isGrouped = ActualXAxis is CategoryAxis && !(ActualXAxis as CategoryAxis).IsIndexed; if (isGrouped) { xValues = GroupedXValuesIndexes; } else { xValues = (ActualXValues is List <double>) ? ActualXValues as List <double> : GetXValues(); } IList <double> x1Values, x2Values, y1Values, y2Values; x1Values = new List <double>(); x2Values = new List <double>(); y1Values = new List <double>(); y2Values = new List <double>(); var stackingValues = GetCumulativeStackValues(this); if (stackingValues != null) { YRangeStartValues = stackingValues.StartValues; YRangeEndValues = stackingValues.EndValues; if (xValues != null) { DoubleRange sbsInfo = this.GetSideBySideInfo(this); if (isGrouped) { Segments.Clear(); Adornments.Clear(); int segmentCount = 0; for (int i = 0; i < DistinctValuesIndexes.Count; i++) { for (int j = 0; j < DistinctValuesIndexes[i].Count; j++) { if (j < xValues.Count) { x1Values.Add(i + sbsInfo.Start); x2Values.Add(i + sbsInfo.End); y1Values.Add(YRangeEndValues[segmentCount]); y2Values.Add(YRangeStartValues[segmentCount]); segmentCount++; } } } if (Segment != null && (IsActualTransposed && Segment is FastStackingColumnSegment) || (!IsActualTransposed && Segment is FastBarBitmapSegment)) { Segments.Clear(); } if (Segment == null || Segments.Count == 0) { if (this.IsActualTransposed) { Segment = new FastBarBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } else { Segment = new FastStackingColumnSegment(x1Values, y1Values, x2Values, y2Values, this); } Segment.SetData(x1Values, y1Values, x2Values, y2Values); this.Segments.Add(Segment); } if (AdornmentsInfo != null) { segmentCount = 0; for (int i = 0; i < DistinctValuesIndexes.Count; i++) { for (int j = 0; j < DistinctValuesIndexes[i].Count; j++) { int index = DistinctValuesIndexes[i][j]; if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Top) { AddColumnAdornments(i, GroupedSeriesYValues[0][index], x1Values[segmentCount], y1Values[segmentCount], segmentCount, sbsInfo.Delta / 2); } else if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Bottom) { AddColumnAdornments(i, GroupedSeriesYValues[0][index], x1Values[segmentCount], y2Values[segmentCount], segmentCount, sbsInfo.Delta / 2); } else { AddColumnAdornments(i, GroupedSeriesYValues[0][index], x1Values[segmentCount], y1Values[segmentCount] + (y2Values[segmentCount] - y1Values[segmentCount]) / 2, segmentCount, sbsInfo.Delta / 2); } segmentCount++; } } } } else { ClearUnUsedAdornments(this.DataCount); if (!this.IsIndexed) { for (int i = 0; i < this.DataCount; i++) { x1Values.Add(xValues[i] + sbsInfo.Start); x2Values.Add(xValues[i] + sbsInfo.End); y1Values.Add(YRangeEndValues[i]); y2Values.Add(YRangeStartValues[i]); } } else { for (int i = 0; i < this.DataCount; i++) { x1Values.Add(i + sbsInfo.Start); x2Values.Add(i + sbsInfo.End); y1Values.Add(YRangeEndValues[i]); y2Values.Add(YRangeStartValues[i]); } } if (Segment != null && (IsActualTransposed && Segment is FastStackingColumnSegment) || (!IsActualTransposed && Segment is FastBarBitmapSegment)) { Segments.Clear(); } if (Segment == null || Segments.Count == 0) { if (this.IsActualTransposed) { Segment = new FastBarBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } else { Segment = new FastStackingColumnSegment(x1Values, y1Values, x2Values, y2Values, this); } Segment.SetData(x1Values, y1Values, x2Values, y2Values); this.Segments.Add(Segment); } else if (xValues != null) { if (Segment is FastBarBitmapSegment) { (Segment as FastBarBitmapSegment).SetData(x1Values, y1Values, x2Values, y2Values); } else { (Segment as FastStackingColumnSegment).SetData(x1Values, y1Values, x2Values, y2Values); } } if (AdornmentsInfo != null) { for (int i = 0; i < this.DataCount; i++) { if (i < this.DataCount) { if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Top) { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y1Values[i], i, sbsInfo.Delta / 2); } else if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Bottom) { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y2Values[i], i, sbsInfo.Delta / 2); } else { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y1Values[i] + (y2Values[i] - y1Values[i]) / 2, i, sbsInfo.Delta / 2); } } } } } } } }
protected internal override void OnPointerMoved(PointerRoutedEventArgs e) { if (ChartArea == null) { return; } if (this.EnableSegmentSelection || this.EnableSeriesSelection) { FrameworkElement element = e.OriginalSource as FrameworkElement; ChartSegment segment = null; if (element != null) { if (element.Tag != null) { segment = element.Tag as ChartSegment; } } if (segment is TrendlineSegment) { return; } if (element.DataContext is LegendItem) { return; } #if __IOS__ || __ANDROID__ var image = (element as Border)?.Child as Image; #else var image = element as Image; #endif if (segment != null && segment.Series is ISegmentSelectable && !(segment.Item is Trendline)) { // Scatter series supports selection and dragging at the same time. if (!(segment.Series is ScatterSeries) && IsDraggableSeries(segment.Series)) { return; } if (!segment.Series.IsLinear || EnableSeriesSelection) { ChangeSelectionCursor(true); } else { ChangeSelectionCursor(false); } if (SelectionMode == Charts.SelectionMode.MouseMove) { if (!segment.Series.IsSideBySide && segment.Series is CartesianSeries && !(segment.Series is ScatterSeries) && !(segment.Series is BubbleSeries)) { Point canvasPoint = e.GetCurrentPoint(segment.Series.ActualArea.GetAdorningCanvas()).Position; ChartDataPointInfo data = (segment.Series as ChartSeries).GetDataPoint(canvasPoint); OnMouseMoveSelection(segment.Series, data); } else { int segIndex = segment.Series is CircularSeriesBase && !double.IsNaN(((CircularSeriesBase)segment.Series).GroupTo) ?segment.Series.Segments.IndexOf(segment): segment.Series.ActualData.IndexOf(segment.Item); OnMouseMoveSelection(segment.Series, segIndex); } } } else if (e.OriginalSource is Shape && (e.OriginalSource as Shape).DataContext is ChartAdornmentContainer && ((e.OriginalSource as Shape).DataContext as ChartAdornmentContainer).Tag is int) { // Check the selected element is adornment shape selectedAdornmentPresenter = VisualTreeHelper.GetParent((e.OriginalSource as Shape).DataContext as ChartAdornmentContainer) as ChartAdornmentPresenter; if (IsDraggableSeries(selectedAdornmentPresenter.Series)) { return; } ChangeSelectionCursor(true); if (SelectionMode == Charts.SelectionMode.MouseMove) { index = (int)((e.OriginalSource as Shape).DataContext as ChartAdornmentContainer).Tag; if (selectedAdornmentPresenter != null && selectedAdornmentPresenter.Series is ISegmentSelectable) { OnMouseMoveSelection(selectedAdornmentPresenter.Series, index); } } } else if (image != null && image.Source is WriteableBitmap) { GetBitmapSeriesCollection(element, e); // Bitmap segment selection process handling. if (SelectionMode == Charts.SelectionMode.MouseMove) { OnBitmapSeriesMouseMoveSelection(element, e); } } else if (element is Border || element is TextBlock || element is Shape) // check the selected element is adornment label { ChangeSelectionCursor(false); FrameworkElement frameworkElement = e.OriginalSource as FrameworkElement; int count = e.OriginalSource is TextBlock ? 3 : 2; for (int i = 0; i < count; i++) { if (frameworkElement != null) { frameworkElement = VisualTreeHelper.GetParent(frameworkElement) as FrameworkElement; } else { break; } } if (frameworkElement is ContentPresenter) { index = ChartExtensionUtils.GetAdornmentIndex(frameworkElement); if (index != -1) { ChangeSelectionCursor(true); } if (SelectionMode == Charts.SelectionMode.MouseMove) { frameworkElement = VisualTreeHelper.GetParent(frameworkElement) as FrameworkElement; if (frameworkElement is ChartAdornmentPresenter || frameworkElement is ChartAdornmentContainer) { while (!(frameworkElement is ChartAdornmentPresenter) && frameworkElement != null) { frameworkElement = VisualTreeHelper.GetParent(frameworkElement) as FrameworkElement; } selectedAdornmentPresenter = frameworkElement as ChartAdornmentPresenter; if (IsDraggableSeries(selectedAdornmentPresenter.Series)) { return; } if (selectedAdornmentPresenter != null && selectedAdornmentPresenter.Series is ISegmentSelectable) { OnMouseMoveSelection(selectedAdornmentPresenter.Series, index); } } } } var contentControl = frameworkElement as ContentControl; if (contentControl != null && contentControl.Tag is int) { ChangeSelectionCursor(true); if (SelectionMode == Charts.SelectionMode.MouseMove) { index = (int)contentControl.Tag; frameworkElement = VisualTreeHelper.GetParent(frameworkElement) as FrameworkElement; var chartAdornmentPresenter = frameworkElement as ChartAdornmentPresenter; if (chartAdornmentPresenter != null) { selectedAdornmentPresenter = chartAdornmentPresenter; if (IsDraggableSeries(selectedAdornmentPresenter.Series)) { return; } if (selectedAdornmentPresenter != null && selectedAdornmentPresenter.Series is ISegmentSelectable) { OnMouseMoveSelection(selectedAdornmentPresenter.Series, index); } } } } } else if (ChartArea.PreviousSelectedSeries != null && ChartArea.CurrentSelectedSeries != null && SelectionMode == Charts.SelectionMode.MouseMove && ChartArea.VisibleSeries.Contains(ChartArea.PreviousSelectedSeries)) { ChangeSelectionCursor(false); bool isCancel; if (EnableSeriesSelection) { isCancel = ChartArea.CurrentSelectedSeries.RaiseSelectionChanging(-1, ChartArea.SeriesSelectedIndex); } else { isCancel = ChartArea.CurrentSelectedSeries.RaiseSelectionChanging( -1, (ChartArea.CurrentSelectedSeries as ISegmentSelectable).SelectedIndex); } if (!isCancel) { Deselect(); } } else { ChangeSelectionCursor(false); } } else { ChangeSelectionCursor(false); } }
internal void UpdateSegmentDragValueToolTipHigh(Point pos, ChartSegment segment, double newValue, double offsetY) { if (!EnableDragTooltip) { return; } if (highTooltip == null) { highDragInfo = new ChartDragSegmentInfo() { PostfixLabelTemplate = ActualYAxis.PostfixLabelTemplate, PrefixLabelTemplate = ActualYAxis.PostfixLabelTemplate }; highTooltip = new ContentControl { Content = highDragInfo }; SeriesPanel.Children.Add(highTooltip); if (DragTooltipTemplate == null) { highTooltip.ContentTemplate = IsActualTransposed ? ChartDictionaries.GenericCommonDictionary["SegmentDragInfoOppRight"] as DataTemplate : ChartDictionaries.GenericCommonDictionary["SegmentDragInfo"] as DataTemplate; } else { highTooltip.ContentTemplate = DragTooltipTemplate; } } highDragInfo.Segment = segment; highDragInfo.Brush = segment.Interior; highDragInfo.ScreenCoordinates = pos; ((ChartDragSegmentInfo)highDragInfo).NewValue = newValue; highDragInfo.Segment = segment; highTooltip.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); if (IsActualTransposed) { if (pos.X < 0) { Canvas.SetTop(highTooltip, pos.Y - highTooltip.DesiredSize.Height / 2); Canvas.SetLeft(highTooltip, 0); } else { Canvas.SetTop(highTooltip, pos.Y - highTooltip.DesiredSize.Height / 2); Canvas.SetLeft(highTooltip, pos.X); } } else { double posY = pos.Y - highTooltip.DesiredSize.Height; if (posY < 0) { Canvas.SetTop(highTooltip, 0); Canvas.SetLeft(highTooltip, pos.X - highTooltip.DesiredSize.Width / 2); } else { Canvas.SetTop(highTooltip, posY); Canvas.SetLeft(highTooltip, pos.X - highTooltip.DesiredSize.Width / 2); } } }
/// <summary> /// Called when DataSource property changed /// </summary> /// <param name="oldValue"></param> /// <param name="newValue"></param> protected override void OnDataSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue) { Segment = null; base.OnDataSourceChanged(oldValue, newValue); }
internal override void SelectedSegmentsIndexes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { ChartSelectionChangedEventArgs chartSelectionChangedEventArgs; ChartSegment prevSelectedSegment = null; if (prevDataPoint != null && Segments.Count > 0) { prevSelectedSegment = (from segment in Segments where segment is FastLineSegment && (segment as FastLineSegment).xChartVals.Contains(prevDataPoint.XData) select segment).FirstOrDefault() as ChartSegment; } switch (e.Action) { case NotifyCollectionChangedAction.Add: if (e.NewItems != null && !(ActualArea.SelectionBehaviour.SelectionStyle == SelectionStyle.Single)) { int oldIndex = PreviousSelectedIndex; int newIndex = (int)e.NewItems[0]; // For adornment selection implementation if (newIndex >= 0 && ActualArea.GetEnableSegmentSelection()) { // Selects the adornment when the mouse is over or clicked on adornments(adornment selection). if (adornmentInfo != null && adornmentInfo.HighlightOnSelection) { UpdateAdornmentSelection(newIndex); } if (ActualArea != null && Segments.Count > 0) { var selectedSegment = (from segment in Segments where segment is FastLineSegment && (segment as FastLineSegment).xChartVals.Contains(dataPoint.XData) select segment).FirstOrDefault(); if (selectedSegment != null) { chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = selectedSegment, SelectedSegments = Area.SelectedSegments, SelectedSeries = this, SelectedIndex = newIndex, PreviousSelectedIndex = oldIndex, NewPointInfo = GetDataPoint(newIndex), IsSelected = true }; chartSelectionChangedEventArgs.PreviousSelectedSeries = this.ActualArea.PreviousSelectedSeries; if (oldIndex != -1) { chartSelectionChangedEventArgs.PreviousSelectedSegment = prevSelectedSegment; chartSelectionChangedEventArgs.OldPointInfo = GetDataPoint(oldIndex); } (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); PreviousSelectedIndex = newIndex; prevDataPoint = dataPoint; } } else if (Segments.Count == 0) { triggerSelectionChangedEventOnLoad = true; } } } break; case NotifyCollectionChangedAction.Remove: if (e.OldItems != null && !(ActualArea.SelectionBehaviour.SelectionStyle == SelectionStyle.Single)) { int newIndex = (int)e.OldItems[0]; chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = null, SelectedSegments = Area.SelectedSegments, SelectedSeries = null, SelectedIndex = newIndex, PreviousSelectedIndex = PreviousSelectedIndex, NewPointInfo = null, OldPointInfo = GetDataPoint(PreviousSelectedIndex), PreviousSelectedSeries = this, IsSelected = false }; if (PreviousSelectedIndex != -1) { chartSelectionChangedEventArgs.PreviousSelectedSegment = prevSelectedSegment; } (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); OnResetSegment(newIndex); PreviousSelectedIndex = newIndex; } break; } }
/// <summary> /// Creates the segments of FastBarBitmapSeries /// </summary> public override void CreateSegments() { var isGrouped = (ActualXAxis is CategoryAxis && !(ActualXAxis as CategoryAxis).IsIndexed); if (isGrouped) { xValues = GroupedXValuesIndexes; } else { xValues = GetXValues(); } IList <double> x1Values, x2Values, y1Values, y2Values; x1Values = new List <double>(); x2Values = new List <double>(); y1Values = new List <double>(); y2Values = new List <double>(); if (xValues != null) { DoubleRange sbsInfo = this.GetSideBySideInfo(this); double origin = ActualXAxis != null ? ActualXAxis.Origin : 0; if (ActualXAxis != null && ActualXAxis.Origin == 0 && ActualYAxis is LogarithmicAxis && (ActualYAxis as LogarithmicAxis).Minimum != null) { origin = (double)(ActualYAxis as LogarithmicAxis).Minimum; } if (isGrouped) { Segments.Clear(); Adornments.Clear(); GroupedActualData.Clear(); for (int i = 0; i < DistinctValuesIndexes.Count; i++) { var list = (from index in DistinctValuesIndexes[i] where GroupedSeriesYValues[0].Count > index select new List <double> { GroupedSeriesYValues[0][index], index }). OrderByDescending(val => val[0]).ToList(); for (int j = 0; j < list.Count; j++) { var yValue = list[j][0]; GroupedActualData.Add(ActualData[(int)list[j][1]]); if (i < xValues.Count && GroupedSeriesYValues[0].Count > i) { x1Values.Add(i + sbsInfo.Start); x2Values.Add(i + sbsInfo.End); y1Values.Add(yValue); y2Values.Add(ActualXAxis != null ? ActualXAxis.Origin : 0); // Setting origin value for fastbar segment } } } if (Segment != null && (!IsActualTransposed && Segment is FastBarBitmapSegment) || (IsActualTransposed && Segment is FastColumnBitmapSegment)) { Segments.Clear(); } if (Segment == null || Segments.Count == 0) { if (IsActualTransposed) { Segment = new FastBarBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } else { Segment = new FastColumnBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } Segment.SetData(x1Values, y1Values, x2Values, y2Values); this.Segments.Add(Segment); } if (AdornmentsInfo != null) { int count = 0; for (int i = 0; i < DistinctValuesIndexes.Count; i++) { var list = (from index in DistinctValuesIndexes[i] select new List <double> { GroupedSeriesYValues[0][index], index }). OrderByDescending(val => val[0]).ToList(); for (int j = 0; j < DistinctValuesIndexes[i].Count; j++) { var yValue = list[j][0]; if (i < xValues.Count) { if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Top) { AddColumnAdornments(i, yValue, x1Values[count], y1Values[count], count, sbsInfo.Delta / 2); } else if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Bottom) { AddColumnAdornments(i, yValue, x1Values[count], y2Values[count], count, sbsInfo.Delta / 2); } else { AddColumnAdornments(i, yValue, x1Values[count], y1Values[count] + (y2Values[count] - y1Values[count]) / 2, count, sbsInfo.Delta / 2); } } count++; } } } } else { if (!this.IsIndexed) { for (int i = 0; i < this.DataCount; i++) { x1Values.Add(xValues[i] + sbsInfo.Start); x2Values.Add(xValues[i] + sbsInfo.End); y1Values.Add(YValues[i]); y2Values.Add(ActualXAxis != null ? ActualXAxis.Origin : 0); // Setting origin value for fastbar segment } } else { for (int i = 0; i < this.DataCount; i++) { x1Values.Add(i + sbsInfo.Start); x2Values.Add(i + sbsInfo.End); y1Values.Add(YValues[i]); y2Values.Add(origin); } } if (Segment != null && (!IsActualTransposed && Segment is FastBarBitmapSegment) || (IsActualTransposed && Segment is FastColumnBitmapSegment)) { Segments.Clear(); } if (Segment == null || Segments.Count == 0) { if (IsActualTransposed) { Segment = new FastBarBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } else { Segment = new FastColumnBitmapSegment(x1Values, y1Values, x2Values, y2Values, this); } Segment.SetData(x1Values, y1Values, x2Values, y2Values); this.Segments.Add(Segment); } if (Segment is FastBarBitmapSegment) { (Segment as FastBarBitmapSegment).Item = ActualData; (Segment as FastBarBitmapSegment).SetData(x1Values, y1Values, x2Values, y2Values); } else { (Segment as FastColumnBitmapSegment).Item = ActualData; (Segment as FastColumnBitmapSegment).SetData(x1Values, y1Values, x2Values, y2Values); } if (AdornmentsInfo != null) { ClearUnUsedAdornments(this.DataCount); for (int i = 0; i < this.DataCount; i++) { if (i < this.DataCount) { if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Top) { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y1Values[i], i, sbsInfo.Delta / 2); } else if (this.AdornmentsInfo.AdornmentsPosition == AdornmentsPosition.Bottom) { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y2Values[i], i, sbsInfo.Delta / 2); } else { AddColumnAdornments(xValues[i], YValues[i], x1Values[i], y1Values[i] + (y2Values[i] - y1Values[i]) / 2, i, sbsInfo.Delta / 2); } } } } } } }
/// <summary> /// Method used to set SegmentSelectionBrush to selectedindex chartsegment /// </summary> /// <param name="newIndex"/> /// <param name="oldIndex"/> protected internal override void SelectedIndexChanged(int newIndex, int oldIndex) { CircularSeriesBase circularseries = this as CircularSeriesBase; bool isGroupTo = circularseries != null && !double.IsNaN(circularseries.GroupTo); ChartSelectionChangedEventArgs chartSelectionChangedEventArgs; if (ActualArea != null && ActualArea.SelectionBehaviour != null) { ChartSegment selectedSegment = null, oldSegment = null; // Reset the oldIndex segment Interior if (ActualArea.SelectionBehaviour.SelectionStyle == SelectionStyle.Single) { if (SelectedSegmentsIndexes.Contains(oldIndex)) { SelectedSegmentsIndexes.Remove(oldIndex); } OnResetSegment(oldIndex); } if (oldIndex != -1 && oldIndex < ActualData.Count) { object oldItem = isGroupTo ? Segments[oldIndex].Item : ActualData[oldIndex]; oldSegment = Segments.Where(segment => segment.Item == oldItem).FirstOrDefault(); } if (newIndex >= 0 && ActualArea.GetEnableSegmentSelection()) { if (!SelectedSegmentsIndexes.Contains(newIndex)) { SelectedSegmentsIndexes.Add(newIndex); } if (Segments.Count == 0) { triggerSelectionChangedEventOnLoad = true; return; } if (newIndex < Segments.Count || newIndex < ActualData.Count) { // For adornment selection implementation if (adornmentInfo is ChartAdornmentInfo && adornmentInfo.HighlightOnSelection) { UpdateAdornmentSelection(newIndex); } // Set the SegmentSelectionBrush to newIndex segment Interior if (this is ISegmentSelectable) { object newItem = isGroupTo ? Segments[newIndex].Item : ActualData[newIndex]; selectedSegment = Segments.Where(segment => segment.Item == newItem).FirstOrDefault(); if (selectedSegment != null) { if (this.SegmentSelectionBrush != null) { selectedSegment.BindProperties(); } selectedSegment.IsSelectedSegment = true; } } } if (newIndex < Segments.Count || newIndex < ActualData.Count) { chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = selectedSegment, SelectedSegments = Area.SelectedSegments, SelectedSeries = this, SelectedIndex = newIndex, PreviousSelectedIndex = oldIndex, PreviousSelectedSegment = oldSegment, NewPointInfo = selectedSegment != null ? selectedSegment.Item : null, OldPointInfo = oldSegment != null ? oldSegment.Item : null, PreviousSelectedSeries = null, IsSelected = true }; if (this.ActualArea.PreviousSelectedSeries != null && oldIndex != -1) { chartSelectionChangedEventArgs.PreviousSelectedSeries = this.ActualArea.PreviousSelectedSeries; } (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); PreviousSelectedIndex = newIndex; } } else if (newIndex == -1) { chartSelectionChangedEventArgs = new ChartSelectionChangedEventArgs() { SelectedSegment = null, SelectedSegments = Area.SelectedSegments, SelectedSeries = null, SelectedIndex = newIndex, PreviousSelectedIndex = oldIndex, PreviousSelectedSegment = oldSegment, NewPointInfo = null, OldPointInfo = oldSegment.Item, PreviousSelectedSeries = this, IsSelected = false }; (ActualArea as SfChart).OnSelectionChanged(chartSelectionChangedEventArgs); PreviousSelectedIndex = newIndex; } } }