protected override void LayoutYValueLabels() { ChartModel model = Model; double marginLeft = MarginLeft, marginTop = MarginTop; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); double cx = marginLeft + gridWidth / 2, cy = marginTop + gridHeight / 2.0; double radius = Math.Min(gridWidth, gridHeight) / 2.0; int vLineCount = this.GetVLineCount(), circleCount = this.GetHLineCount(); double minValue = model.MinYValue, maxValue = model.MaxYValue; string labelXAML = CurrentLookAndFeel.GetYValueLabelXAML(); double textHeight = double.NaN; _addRadarYLabelAt(labelXAML, cx, (double)marginTop, ref textHeight, maxValue); _addRadarYLabelAt(labelXAML, cx, cy, ref textHeight, minValue); // horizontal lines for (int i = 0; i < circleCount - 1; ++i) { double newRadius = (i + 1) * radius / (double)circleCount; double value = ((maxValue - minValue) * (i + 1) / (double)circleCount) + minValue; this._addRadarYLabelAt(labelXAML, cx, radius - newRadius + marginTop, ref textHeight, value); } }
protected virtual void SetIndicatorPosition(double yValue, UIElement indicator, double ratio) { double theta, cx = _animCenter.X, cy = _animCenter.Y; ChartModel model = Model; double minValue = model.MinYValue, maxValue = model.MaxYValue; double valueRatio = ratio * (yValue - minValue) / (maxValue - minValue); theta = Math.PI / 6 + valueRatio * (5 * Math.PI / 3); if (theta < Math.PI / 2) { theta += 3 * Math.PI / 2; } else { theta -= Math.PI / 2; } theta *= 180 / Math.PI; RotateTransform rt = new RotateTransform(); rt.CenterX = cx; rt.CenterY = cy; rt.Angle = theta; indicator.RenderTransform = rt; }
protected override void LayoutGroupLabels() { ChartModel model = Model; double marginLeft = MarginLeft, marginTop = MarginTop; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight, cy = 0; double cx = marginLeft + gridWidth / 2, radius = 0; string [] groupLabels = model.GroupLabels; int vLineCount = groupLabels.Length; TextBlock labelElem; double groupWidth = gridWidth / (double)vLineCount; Canvas container = HLabelContainer; UIElementCollection childNodes = container.Children; bool firstLabelDrawn = false; TextBlock[] gLabelElems = GroupLabelElems; if (childNodes.Count == 0) { return; } for (int i = 0; i < vLineCount; ++i) { labelElem = gLabelElems[i]; if (labelElem == null) { continue; } if (!firstLabelDrawn) { gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); cy = marginTop + gridHeight / (double)2; radius = Math.Min(gridWidth, gridHeight) / (double)2 + labelElem.ActualHeight - _TEXT_MARGIN / (double)2; firstLabelDrawn = true; } double theta = (i) * 2 * Math.PI / (double)vLineCount; double dx = cx + radius * Math.Sin(theta), dy = cy - radius * Math.Cos(theta); labelElem.SetValue(Canvas.TopProperty, dy - labelElem.ActualHeight / (double)2); if (theta > Math.PI) { dx -= labelElem.ActualWidth; } labelElem.SetValue(Canvas.LeftProperty, dx); } }
/// <summary> /// Draws the dial for the gauge and returns the actual size of the gauge /// </summary> /// <param name="gaugeContainer"></param> /// <param name="quadWidth"></param> /// <param name="quadHeight"></param> /// <param name="iGroup"></param> /// <returns></returns> protected virtual Size DrawDial( Canvas gaugeContainer, double quadWidth, double quadHeight, int iGroup) { ChartModel model = Model; if (iGroup == -1) { iGroup = 0; } List <UIElement> dataElems = DataElements; bool animate = (AnimationDuration > 0); Canvas gauge = XamlReader.Load(GetGaugeXAML()) as Canvas; gaugeContainer.Children.Add(gauge); double gaugeWidth = gauge.Width, gaugeHeight = gauge.Height; double gaugeR = gaugeWidth / 2; Canvas indicator = gauge.FindName("indicator") as Canvas; SetExpandosOnElement(indicator, iGroup, 0, new Point()); if (DisplayToolTip) { indicator.MouseEnter += new MouseEventHandler(ShowToolTip); indicator.MouseLeave += new MouseEventHandler(HideToolTip); } indicator.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); if (_animCenter.X == 0) { _animCenter.X = _animCenter.Y = indicator.Width / 2; } if (animate) { dataElems.Add(indicator); } else { // If there is no animation lets move the indicators to the last position SetIndicatorPosition(model.YValues[iGroup, 0], indicator, 1); } CreateTextMarkerGroup(gauge, gaugeR); return(ScaleGauge(gauge, quadWidth, quadHeight, gaugeWidth, gaugeHeight)); }
protected override ChartEventArgs GetChartEvent(object sender, MouseEventArgs e) { Point pt = e.GetPosition(ChartCanvas); ElementExpandos ee = Expandos[sender]; int i = ee.SeriesIndex; bool isPerspective = IsPerspective; double yOffset = YOffsetPerspective; ChartModel model = Model; double[,] xValues = model.XValues; double[,] yValues = model.YValues; int nValues = yValues.GetUpperBound(0) + 1; double minYValue = model.MinYValue, maxYValue = model.MaxYValue; double minXValue = model.MinXValue, maxXValue = model.MaxXValue; double marginLeft = MarginLeft, marginTop = MarginTop; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); double gridBottom = gridHeight + marginTop + (isPerspective?yOffset:0); double dx, dy, xValue = 0.0, yValue = 0.0; double nextdy, nextdx; for (int j = 0; j < nValues; ++j) { if (j != nValues - 1) { dx = marginLeft + gridWidth * (xValues[j, i] - minXValue) / (maxXValue - minXValue); nextdx = marginLeft + gridWidth * (xValues[j + 1, i] - minXValue) / (maxXValue - minXValue); if (pt.X > dx && pt.X < (dx + nextdx)) { dy = gridBottom - gridHeight * (yValues[j, i] - minYValue) / (maxYValue - minYValue); nextdy = gridBottom - gridHeight * (yValues[j + 1, i] - minYValue) / (maxYValue - minYValue); yValue = yValues[j, i] + (yValues[j + 1, i] - yValues[j, i]) * (pt.Y - dy) / (nextdy - dy); xValue = xValues[j, i] + (xValues[j + 1, i] - xValues[j, i]) * (pt.X - dx) / (nextdx - dx); break; } } } int[] seriesIndices = { i }; //double[] yEventValues = {yValue}; //double[] xEventValues = {xValue}; return(new ChartEventArgs(seriesIndices, null, new double[] { yValue }, new double[] { xValue })); }
public override void SetDataAnimStep(double ratio) { double marginLeft = MarginLeft, marginTop = MarginTop; bool isRadarArea = (Type == Chart.ChartType.RADAR_AREA); ChartModel model = Model; string [] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); double cx = marginLeft + gridWidth / 2.0, cy = marginTop + gridHeight / 2.0; double newRatio = ratio * (double)seriesCount; int animSeriesIndex = 0; if (newRatio > 1) { animSeriesIndex = (int)Math.Floor(newRatio); if (animSeriesIndex >= seriesCount) { animSeriesIndex = seriesCount - 1; } newRatio = newRatio - (int)Math.Floor(newRatio); } double tx = (1 - newRatio) * cx, ty = (1 - newRatio) * cy; Matrix m = new Matrix(newRatio, 0, 0, newRatio, tx, ty); // We will make each series appear separately int i = animSeriesIndex; this._setRadarSeriesAnimStep(i, isRadarArea, m); if (i > 0) { _setRadarSeriesAnimStep(i - 1, isRadarArea, Matrix.Identity); } // make sure that everything is scaled properly at the end if (ratio == 1) { for (int j = 0; j < seriesCount; ++j) { _setRadarSeriesAnimStep(j, isRadarArea, Matrix.Identity); } _dotElements = null; } }
protected override void DrawGroupLabels() { ChartModel model = Model; Canvas container = new Canvas(); HLabelContainer = container; List <UIElement> labelElems = LabelElements; bool animate = (AnimationDuration > 0); string[] groupLabels = model.GroupLabels; int vLineCount = groupLabels.Length; TextBlock labelElem; string labelText; string labelXAML = CurrentLookAndFeel.GetGroupLabelXAML(); double maxWidth = 0, maxHeight = 0; TextBlock [] gLabelElems = new TextBlock[vLineCount]; GroupLabelElems = gLabelElems; for (int i = 0; i < vLineCount; ++i) { labelText = groupLabels[i]; if (labelText == null || labelText.Length == 0) { continue; } labelElem = XamlReader.Load(labelXAML) as TextBlock; if (animate) { labelElems.Add(labelElem); labelElem.Opacity = 0; } labelElem.Text = labelText; container.Children.Add(labelElem); gLabelElems[i] = labelElem; maxWidth = Math.Max(maxWidth, labelElem.ActualWidth); maxHeight = Math.Max(maxHeight, labelElem.ActualHeight); } ChartCanvas.Children.Add(container); HLabelBounds = new Size(maxWidth, maxHeight); }
protected override Size FillToolTipData( object sender, MouseEventArgs e, Path boundingRectElem, Path circleElem) { ChartEventArgs chartEvent = GetChartEvent(sender, e); int i = chartEvent.SeriesIndices[0]; double yValue = chartEvent.YValues[0], xValue = chartEvent.XValues[0]; ChartModel model = Model; string[] seriesLabels = model.SeriesLabels; TextBlock textElem = ToolTip.Children[2] as TextBlock; textElem.Text = seriesLabels[i] + ": (" + xValue.ToString(Format) + ") (" + yValue.ToString() + ")"; double labelWidth = textElem.ActualWidth; double labelHeight = textElem.ActualHeight; //We do not need the next label textElem = ToolTip.Children[3] as TextBlock; textElem.Text = ""; double rectWidth = labelWidth + 2 * _TEXT_MARGIN; RectangleGeometry rg = boundingRectElem.Data as RectangleGeometry; Rect rect = rg.Rect; double rectHeight = rect.Height; if (rectHeight > 2 * labelHeight) { rectHeight -= labelHeight; } rg.Rect = new Rect(rect.X, rect.Y, rectWidth, rectHeight); boundingRectElem.SetValue(Path.StrokeProperty, new SolidColorBrush(Model.SeriesColors[i])); EllipseGeometry eg = circleElem.Data as EllipseGeometry; eg.RadiusX = eg.RadiusY = 0; return(new Size(rectWidth, 2 * (labelHeight + _TEXT_MARGIN))); }
protected override ChartEventArgs GetChartEvent(object sender, MouseEventArgs e) { Point pt = e.GetPosition(ChartCanvas); ElementExpandos ee = Expandos[sender]; int i = ee.SeriesIndex; bool isPerspective = IsPerspective; double yOffset = YOffsetPerspective; ChartModel model = Model; double [,] yValues = model.YValues; string [] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; double marginLeft = MarginLeft, marginTop = MarginTop; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); int yValueCount = yValues.GetUpperBound(0) + 1; double barWidth = (gridWidth / Math.Max(yValueCount, groupCount)); double gridBottom = gridHeight + marginTop + (isPerspective?yOffset:0); double dx = marginLeft + barWidth / 2, value = 0.0; for (int j = 0; j < yValueCount; ++j) { if (j == yValueCount - 1) { continue; } if (pt.X > dx && pt.X < (dx + barWidth)) { value = yValues[j, i] + (yValues[j + 1, i] - yValues[j, i]) * (pt.X - dx) / barWidth; break; } dx += barWidth; } int[] seriesIndices = { i }; double[] values = { value }; return(new ChartEventArgs(seriesIndices, null, values, null)); }
public override void SetDataAnimStep(double ratio) { List <UIElement> animElems = DataElements; int animCount = animElems.Count; ChartModel model = Model; double[,] yValues = Model.YValues; for (int i = 0; i < animCount; ++i) { // For Dial Chart only one value is applicable double yValue = yValues[i, 0]; SetIndicatorPosition(yValue, animElems[i], ratio); } }
protected override void SetIndicatorPosition(double yValue, UIElement indicator, double ratio) { double cx = _animCenter.X, cy = _animCenter.Y; ChartModel model = Model; double minValue = model.MinYValue, maxValue = model.MaxYValue; double valueRatio = ratio * (yValue - minValue) / (maxValue - minValue); double theta = valueRatio * Math.PI; theta *= 180 / Math.PI; RotateTransform rt = new RotateTransform(); rt.CenterX = cx; rt.CenterY = cy; rt.Angle = theta; indicator.RenderTransform = rt; }
public override void DrawChartData() { var rootElem = ChartCanvas; // calculate the number of rows and columns ChartModel model = Model; double[,] yValues = model.YValues; int yValueCount = yValues.GetUpperBound(0) + 1; string[] groupLabels = model.GroupLabels; int groupCount = groupLabels != null?groupLabels.Length:1; int nCols = (int)Math.Ceiling(Math.Sqrt(yValueCount)), nRows = (int)Math.Round(Math.Sqrt(yValueCount)); string labelXAML = CurrentLookAndFeel.GetGroupLabelXAML(); TextBlock labelElem = null; double dx = MarginLeft, dy = MarginTop; double quadWidth = (rootElem.Width - dx - MarginRight) / nCols; bool animate = (AnimationDuration > 0); double vGap = 2 * _TEXT_MARGIN; var quadHeight = (rootElem.Height - MarginTop - MarginBottom - (nRows - 1) * vGap) / nRows; if (animate) { _pieAnimAngles = new List <double>(); _pieAnimRadii = new List <double>(); } for (int i = 0; i < nRows; ++i) { for (int j = 0; j < nCols; ++j) { int iGroup = (groupLabels != null)?(i * nCols + j):(-1); if (iGroup >= yValueCount) { break; } string groupLabel = (iGroup == -1)?null:groupLabels[iGroup]; Canvas pieContainer = new Canvas(); rootElem.Children.Add(pieContainer); double newHeight = DrawGroupLabelTitle(groupLabel, rootElem, labelXAML, ref labelElem, dx, dy, quadWidth, quadHeight); double newWidth = quadWidth - 2 * _TEXT_MARGIN; double cx = dx + quadWidth / 2 + _TEXT_MARGIN, cy = dy + newHeight / 2; if (animate) { _pieAnimRadii.Add(Math.Max(cx, cy)); } if (IsPerspective) { this._draw3DPies(pieContainer, newWidth, newHeight, iGroup); MatrixTransform mt = new MatrixTransform(); mt.Matrix = new Matrix(1, 0, 0, .707, cx, cy); // The chart is draw with the center at 0 so we need to compensate for it. pieContainer.RenderTransform = mt; } else { this._drawPies(pieContainer, newWidth, newHeight, iGroup); TranslateTransform tt = new TranslateTransform(); tt.X = cx; tt.Y = cy; pieContainer.RenderTransform = tt; } dx += quadWidth; } dx = MarginLeft; dy += quadHeight + vGap; } }
public PieChart(ChartType type, ChartModel model) : base(type, model) { }
public ScatterPlotChart(ChartType type, ChartModel model) : base(type, model) { }
protected virtual void CreateTextMarkerGroup(Canvas gauge, double gaugeR) { ChartModel model = Model; Canvas gElem = new Canvas(); gauge.Children.Add(gElem); LookAndFeel lf = CurrentLookAndFeel; int majorMarkerCount = YMajorGridCount; int minorMarkerCount = YMinorGridCount; string majorMarkerXAML = lf.GetGauageMarkerMajorXAML(), minorMarkerXAML = lf.GetGauageMarkerMinorXAML(); string textXAML = lf.GetGauageTextXAML(); TextBlock textElem; Canvas markerContainerCanvas = gauge.FindName("markerContainer") as Canvas; double markerContainerR = markerContainerCanvas.Width / 2; double minValue = model.MinYValue, maxValue = model.MaxYValue; double x, y, angle, textMargin = 0.0; double theta = Math.PI / 6; for (int i = 0; i <= majorMarkerCount; ++i, theta += (5.0 * Math.PI / 3.0) / majorMarkerCount) { double adjustedTheta; if (theta < Math.PI / 2) { adjustedTheta = theta + 3.0 * Math.PI / 2.0; } else { adjustedTheta = theta - Math.PI / 2.0; } x = gaugeR - markerContainerR * (Math.Cos(adjustedTheta)); y = gaugeR - markerContainerR * (Math.Sin(adjustedTheta)); angle = adjustedTheta * 180 / Math.PI; Path marker = XamlReader.Load(majorMarkerXAML) as Path; TransformGroup tg = new TransformGroup(); TranslateTransform tt = new TranslateTransform(); RotateTransform rt = new RotateTransform(); tt.X = x; tt.Y = y; rt.Angle = angle; tg.Children.Add(rt); tg.Children.Add(tt); marker.RenderTransform = tg; gElem.Children.Add(marker); double value = minValue + i * (maxValue - minValue) / (majorMarkerCount); textElem = XamlReader.Load(textXAML) as TextBlock; textElem.Text = value.ToString(Format); if (i == 0) { textMargin = textElem.ActualHeight / 2; } x = gaugeR - (markerContainerR - textMargin) * (Math.Cos(adjustedTheta)); y = gaugeR - (markerContainerR - textMargin) * (Math.Sin(adjustedTheta)); if (theta >= 5 * Math.PI / 6 && theta <= 7 * Math.PI / 6) { x -= textElem.ActualWidth / 2; } else { y -= textElem.ActualHeight / 2; if (theta < Math.PI) { x += 2 * _TEXT_MARGIN; } else { x -= textElem.ActualWidth + 2 * _TEXT_MARGIN; } } tt = new TranslateTransform(); tt.X = x; tt.Y = y; textElem.RenderTransform = tt; gElem.Children.Add(textElem); } theta = Math.PI / 6 + (5 * Math.PI / 3) / (majorMarkerCount * minorMarkerCount); for (int i = (minorMarkerCount + 1); i <= (majorMarkerCount + 1) * minorMarkerCount; ++i, theta += (5 * Math.PI / 3) / (majorMarkerCount * minorMarkerCount)) { if (i % minorMarkerCount == 0) { continue; } double adjustedTheta; if (theta < Math.PI / 2) { adjustedTheta = theta + 3 * Math.PI / 2; } else { adjustedTheta = theta - Math.PI / 2; } x = gaugeR - markerContainerR * (Math.Cos(adjustedTheta)); y = gaugeR - markerContainerR * (Math.Sin(adjustedTheta)); angle = adjustedTheta * 180 / Math.PI; Path marker = XamlReader.Load(minorMarkerXAML) as Path; TransformGroup tg = new TransformGroup(); TranslateTransform tt = new TranslateTransform(); RotateTransform rt = new RotateTransform(); tt.X = x; tt.Y = y; rt.Angle = angle; tg.Children.Add(rt); tg.Children.Add(tt); marker.RenderTransform = tg; gElem.Children.Add(marker); } }
private void _drawPerspectiveBars(int mod, int rem) { bool animate = (this.AnimationDuration > 0); double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective; double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight - xOffset); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom - yOffset); LookAndFeel lf = CurrentLookAndFeel; string pathXAML = lf.GetBarPathXAML(); Path pathElem; List <UIElement> dataElems = null; MatrixTransform defaultTransform = null; if (animate) { dataElems = DataElements; } int barItemPadding = _BARITEM_PADDING; bool isStacked = (Type == ChartType.HBAR_STACKED); ChartModel model = Model; string[] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; string[] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color[] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minValue = model.MinYValue, maxValue = model.MaxYValue; // For combo graphs we display every once in mod int seriesBars = (mod > 1) ? (int)Math.Ceiling(1 / (double)mod) : seriesCount; int yValueCount = yValues.GetUpperBound(0) + 1; double barHeight, stackBase = minValue; if (isStacked) { barHeight = gridHeight / Math.Max(yValueCount, groupCount) - 2 * barItemPadding; } else { barHeight = (gridHeight / Math.Max(yValueCount, groupCount) - 2 * barItemPadding - (seriesCount) * barItemPadding) / seriesBars; } double dx = marginLeft, dy = gridHeight + marginTop + yOffset, barWidth; string gradientXAML = lf.GetElementGradientXAML(); for (int i = 0; i < yValueCount; ++i) { dy -= barItemPadding; dx = marginLeft; for (var j = 0; j < seriesCount; ++j) { // for combo charts we draw a bar every once in a mod. if ((mod > 1) && j % mod != rem) { continue; } // If we use non zero min and it is a stacked graph, we need to remove the min for only // the first series. if (isStacked) { stackBase = (j == 0 ? minValue : 0); } barWidth = gridWidth * (yValues[i, j] - stackBase) / (maxValue - minValue); StringBuilder sb = new StringBuilder(); sb.Append("M").Append(dx).Append(",").Append(dy); sb.Append(" h").Append(barWidth); sb.Append(" v").Append(-barHeight); sb.Append(" h").Append(-barWidth); sb.Append(" v").Append(barHeight); sb.Append(" M").Append(dx).Append(",").Append(dy - barHeight); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); sb.Append(" h").Append(barWidth); sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset); sb.Append(" z"); sb.Append(" M").Append(dx + barWidth).Append(",").Append(dy); sb.Append(" v").Append(-barHeight); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); sb.Append(" v").Append(barHeight); sb.Append(" z"); pathElem = CreatePathFromXAMLAndData(lf.GetBarPathXAML(), sb); if (animate) { dataElems.Add(pathElem); defaultTransform = new MatrixTransform(); Matrix m = new Matrix(); m.M11 = 0.0; defaultTransform.Matrix = m; pathElem.SetValue(UIElement.RenderTransformProperty, defaultTransform); } pathElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[j])); if (gradientXAML != null) { SetGradientOnElement(pathElem, gradientXAML, seriesColors[j], 0xe5); } else { SetFillOnElement(pathElem, seriesColors[j]); } SetExpandosOnElement(pathElem, i, j, new Point(dx + barWidth + (xOffset) / 2.0, dy - (barHeight + yOffset) / 2.0)); if (DisplayToolTip) { pathElem.MouseEnter += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); ChartCanvas.Children.Add(pathElem); if (isStacked) { dx += barWidth; } else { dy -= barHeight; dy -= barItemPadding; } } if (isStacked) { dy -= barHeight; } dy -= barItemPadding; } }
public AreaChart(ChartType type, ChartModel model) : base(type, model) { }
public override void DrawChartData() { if (YMinorGridCount < 0) { YMinorGridCount = 4; } var rootCanvas = ChartCanvas; // calculate the number of rows and columns ChartModel model = Model; double[,] yValues = model.YValues; int yValueCount = yValues.GetUpperBound(0) + 1; string [] groupLabels = model.GroupLabels; int groupCount = (groupLabels != null)?groupLabels.Length:1; int nCols = (int)Math.Ceiling(Math.Sqrt(yValueCount)), nRows = (int)Math.Round(Math.Sqrt(yValueCount)); double dx = MarginLeft, dy = MarginTop; double quadWidth = (rootCanvas.Width - MarginLeft - MarginRight) / nCols; double vGap = 2 * _TEXT_MARGIN; double quadHeight = (rootCanvas.Height - MarginTop - MarginBottom - (nRows - 1) * vGap) / nRows; string labelXAML = CurrentLookAndFeel.GetGroupLabelXAML(); TextBlock labelElem = null; for (int i = 0; i < nRows; ++i) { for (int j = 0; j < nCols; ++j) { int iGroup = groupLabels != null?(i * nCols + j):(-1); if (iGroup >= yValueCount) { break; } string groupLabel = (iGroup == -1)?null:groupLabels[iGroup]; Canvas gaugeContainer = new Canvas(); rootCanvas.Children.Add(gaugeContainer); if (groupLabel != null) { labelElem = XamlReader.Load(labelXAML) as TextBlock; } double newHeight = DrawGroupLabelTitle(groupLabel, rootCanvas, labelXAML, ref labelElem, dx, dy, quadWidth, quadHeight); double newWidth = quadWidth - 2 * _TEXT_MARGIN; Size gaugeSize = DrawDial(gaugeContainer, newWidth, newHeight, iGroup); TranslateTransform tt = new TranslateTransform(); tt.X = (dx + _TEXT_MARGIN); tt.Y = dy; gaugeContainer.RenderTransform = tt; if (groupLabel != null) { if (gaugeSize.Height < newHeight - vGap) { var newY = (double)labelElem.GetValue(Canvas.TopProperty); newY -= (newHeight - gaugeSize.Height) / 2 - vGap; labelElem.SetValue(Canvas.TopProperty, newY); } } dx += quadWidth; } dx = MarginLeft; dy += quadHeight + vGap; } }
protected override ChartEventArgs GetChartEvent(object sender, MouseEventArgs e) { Point pt = e.GetPosition(ChartCanvas); bool isStacked = (Type == ChartType.AREA_STACKED); ChartModel model = Model; bool isPerspective = IsPerspective; double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective; string [] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; double[,] yValues = model.YValues; double minValue = model.MinYValue, maxValue = model.MaxYValue; int yValueCount = yValues.GetUpperBound(0) + 1; double marginLeft = MarginLeft, marginTop = MarginTop; double gridWidth = (ChartCanvas.Width - marginLeft - MarginRight); double gridHeight = (ChartCanvas.Height - marginTop - MarginBottom); double barWidth = (gridWidth / (Math.Max(yValueCount, groupCount))); if (isPerspective) { gridWidth -= xOffset; gridHeight -= yOffset; } if (pt.X < marginLeft || pt.X > (marginLeft + gridWidth + (isPerspective?xOffset:0)) || pt.Y < marginTop || pt.Y > (marginTop + gridHeight + (isPerspective?yOffset:0))) { return(null); } int seriesCount = model.SeriesLabels.Length; double stackBase; bool insideStacked = false; double dx, dy, dy1, dy2, value; List <int> seriesIndices = new List <int>(seriesCount); List <double> seriesValues = new List <double>(seriesCount); double[] cumYs = isStacked? new double[yValueCount] : null; if (isStacked) { cumYs = new double[yValueCount]; for (int j = 0; j < yValueCount; ++j) { cumYs[j] = double.NaN; } } double gridBottom = gridHeight + marginTop + (isPerspective?yOffset:0); _seriesYs = new List <double>(seriesCount); for (int i = 0; i < seriesCount && !insideStacked; ++i) { // for combo charts we draw a bar every once in a mod. if ((_mod > 1) && (i % _mod) != _rem) { continue; } dx = marginLeft + barWidth / 2; stackBase = (i == 0?minValue:0); for (int j = 0; j < yValueCount; ++j) { if (isStacked) { if (double.IsNaN(cumYs[j])) { cumYs[j] = gridBottom; } if ((j != yValueCount - 1) && double.IsNaN(cumYs[j + 1])) { cumYs[j + 1] = gridBottom; } cumYs[j] -= gridHeight * (yValues[j, i] - stackBase) / (maxValue - minValue); } if (j == yValueCount - 1) { continue; } if (pt.X > dx && pt.X < (dx + barWidth)) { if (isStacked) { dy1 = cumYs[j]; dy2 = (cumYs[j + 1] - gridHeight * (yValues[j + 1, i] - stackBase) / (maxValue - minValue)); dy = dy1 - (dy1 - dy2) * (pt.X - dx) / barWidth; if (pt.Y >= dy) { value = yValues[j, i] + (yValues[j + 1, i] - yValues[j, i]) * (pt.X - dx) / barWidth; seriesValues.Add(value); seriesIndices.Add(i); _seriesYs.Add(dy); insideStacked = true; break; } } else { dy1 = gridBottom - gridHeight * (yValues[j, i] - minValue) / (maxValue - minValue); dy = dy1 - (gridHeight * (yValues[j + 1, i] - yValues[j, i]) / (maxValue - minValue)) * (pt.X - dx) / barWidth; // find all the series that the y point matches if (dy <= pt.Y) { value = yValues[j, i] + (yValues[j + 1, i] - yValues[j, i]) * (pt.X - dx) / barWidth; seriesValues.Add(value); seriesIndices.Add(i); _seriesYs.Add(dy); } break; } } dx += barWidth; } } return(new ChartEventArgs(seriesIndices.ToArray(), null, seriesValues.ToArray(), null)); }
internal XYLineChart(ChartType type, ChartModel model) : base(type, model) { }
private void _drawPerspectiveXYValues() { bool animate = (this.AnimationDuration > 0); double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective; double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight - xOffset); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom - yOffset); LookAndFeel lf = CurrentLookAndFeel; string pathXAML = lf.GetLinePath3DXAML(); Path pathElem; List <UIElement> dataElems = null; if (animate) { dataElems = DataElements; } ChartModel model = Model; string[] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color[] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minYValue = model.MinYValue, maxYValue = model.MaxYValue; int nValues = yValues.GetUpperBound(0) + 1; double[,] xValues = model.XValues; double minXValue = model.MinXValue, maxXValue = model.MaxXValue; double gridBottom = gridHeight + marginTop + yOffset; double dx, dy; string gradientXAML = lf.GetElementGradientXAML(); MatrixTransform defaultTransform; for (int i = 0; i < seriesCount; ++i) { StringBuilder sb = new StringBuilder(); for (var j = 0; j < nValues; ++j) { dy = gridBottom - gridHeight * (yValues[j, i] - minYValue) / (maxYValue - minYValue); dx = marginLeft + gridWidth * (xValues[j, i] - minXValue) / (maxXValue - minXValue); if (j != nValues - 1) { sb.Append(" M").Append(dx).Append(",").Append(dy); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); double nextdy, nextdx; nextdx = marginLeft + gridWidth * (xValues[j + 1, i] - minXValue) / (maxXValue - minXValue); nextdy = gridBottom - gridHeight * (yValues[j + 1, i] - minYValue) / (maxYValue - minYValue); sb.Append(" L").Append(nextdx + xOffset).Append(",").Append(nextdy - yOffset); sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset); sb.Append(" L").Append(dx).Append(",").Append(dy); } } pathElem = CreatePathFromXAMLAndData(pathXAML, sb); if (animate) { dataElems.Add(pathElem); defaultTransform = new MatrixTransform(); Matrix m = new Matrix(); m.M11 = 0.0; defaultTransform.Matrix = m; pathElem.SetValue(UIElement.RenderTransformProperty, defaultTransform); } if (gradientXAML != null) { SetGradientOnElement(pathElem, gradientXAML, seriesColors[i], 0xC0); } else { SetFillOnElement(pathElem, seriesColors[i]); } pathElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[i])); (pathElem.Data as PathGeometry).FillRule = FillRule.Nonzero; SetExpandosOnElement(pathElem, -1, i, new Point()); if (DisplayToolTip) { pathElem.MouseMove += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); ChartCanvas.Children.Add(pathElem); } }
private void _drawBars(int mod, int rem) { bool animate = (this.AnimationDuration > 0); double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom); LookAndFeel lf = CurrentLookAndFeel; string rectXAML = lf.GetBarPathXAML(); Path rectElem; List <UIElement> dataElems = null; MatrixTransform defaultTransform = null; if (animate) { dataElems = DataElements; } int barItemPadding = _BARITEM_PADDING; bool isStacked = (Type == ChartType.HBAR_STACKED); ChartModel model = Model; string[] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; string[] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color[] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minValue = model.MinYValue, maxValue = model.MaxYValue; // For combo graphs we display every once in mod double barDivider = isStacked ? 1 : ((mod > 1) ? Math.Ceiling(seriesCount / mod) : seriesCount); double stackBase = minValue; int yValueCount = yValues.GetUpperBound(0) + 1; double barHeight = (gridHeight / Math.Max(yValueCount, groupCount) - 2 * barItemPadding) / barDivider; double dx = marginLeft, dy = gridHeight + marginTop, barWidth; string gradientXAML = lf.GetElementGradientXAML(); for (int i = 0; i < yValueCount; ++i) { dy -= barItemPadding; dx = marginLeft; for (int j = 0; j < seriesCount; ++j) { // for combo charts we draw a bar every once in a mod. if ((mod > 1) && (j % mod) != rem) { continue; } // If we use non zero min and it is a stacked graph, we need to remove the min for only // the first series. if (isStacked) { stackBase = (j == 0 ? minValue : 0); } rectElem = XamlReader.Load(rectXAML) as Path; if (animate) { dataElems.Add(rectElem); // FIXTHIS: This is inefficient. However Silverlight currently does not allow sharing transform attribute defaultTransform = new MatrixTransform(); Matrix m = new Matrix(); m.M11 = 0.0; defaultTransform.Matrix = m; rectElem.SetValue(UIElement.RenderTransformProperty, defaultTransform); } barWidth = gridWidth * (yValues[i, j] - stackBase) / (maxValue - minValue); RectangleGeometry rectGeometry = new RectangleGeometry(); rectGeometry.RadiusX = rectGeometry.RadiusY = 2; rectGeometry.Rect = new Rect(dx, dy - barHeight, barWidth, barHeight); rectElem.SetValue(Path.DataProperty, rectGeometry); if (gradientXAML != null) { SetGradientOnElement(rectElem, gradientXAML, seriesColors[j], 0xe5); } else { SetFillOnElement(rectElem, seriesColors[j]); } rectElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[j])); if (isStacked) { dx += barWidth; } SetExpandosOnElement(rectElem, i, j, new Point(dx + barWidth, dy - barHeight / 2.0)); if (DisplayToolTip) { rectElem.MouseEnter += new MouseEventHandler(ShowToolTip); rectElem.MouseLeave += new MouseEventHandler(HideToolTip); } rectElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); ChartCanvas.Children.Add(rectElem); if (!isStacked) { dy -= barHeight; } } if (isStacked) { dy -= barHeight; } dy -= barItemPadding; } }
private void _drawPies( Canvas pieContainer, double quadWidth, double quadHeight, int iGroup) { ChartModel model = Model; double[,] yValues = model.YValues; string [] groupLabels = model.GroupLabels; Color[] seriesColors = model.SeriesColors; var pieSize = Math.Min(quadWidth / 2, quadHeight / 2); if (iGroup == -1) { iGroup = 0; } double nPies = yValues.GetUpperBound(1) + 1; double pieTotal = 0; for (int i = 0; i < nPies; ++i) { pieTotal += yValues[iGroup, i]; } string pathXAML = CurrentLookAndFeel.GetPiePathXAML(); Path pathElem; double pieStart = 0, animAngleStart = 0; List <UIElement> dataElems = null; bool animate = (AnimationDuration > 0); if (animate) { dataElems = DataElements; } string gradientXAML = CurrentLookAndFeel.GetElementGradientXAML(); TranslateTransform defaultTransform; for (int i = 0; i < nPies; ++i) { double valueRatio = 1 - (yValues[iGroup, i]) / (pieTotal); double x1 = pieSize * Math.Cos(pieStart * Math.PI * 2), y1 = pieSize * Math.Sin(pieStart * Math.PI * 2); StringBuilder sb = new StringBuilder(); sb.Append("M0,0 L"); sb.Append(x1); sb.Append(",").Append(y1); double x2 = pieSize * Math.Cos((pieStart + valueRatio) * Math.PI * 2), y2 = pieSize * Math.Sin((pieStart + valueRatio) * Math.PI * 2); if (valueRatio >= .5) // major arc { sb.Append(" A").Append(pieSize).Append(" ").Append(pieSize).Append(" 1 0 0 "); } else { sb.Append(" A").Append(pieSize).Append(" ").Append(pieSize).Append(" 1 1 0 "); } sb.Append(x2); sb.Append(",").Append(y2); sb.Append(" z"); pathElem = CreatePathFromXAMLAndData(pathXAML, sb); if (animate) { dataElems.Add(pathElem); defaultTransform = new TranslateTransform(); defaultTransform.X = defaultTransform.Y = -10000; pathElem.SetValue(Canvas.RenderTransformProperty, defaultTransform); double curAnimRatio = (yValues[iGroup, i]) / (pieTotal); _pieAnimAngles.Add(animAngleStart + curAnimRatio / 2); animAngleStart += curAnimRatio; } if (gradientXAML != null) { SetGradientOnElement(pathElem, gradientXAML, seriesColors[i], 0xe5); } else { SetFillOnElement(pathElem, seriesColors[i]); } pathElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[i])); // centroid of the triangle used for tooltips Point centroid = new Point((x1 + x2) / 3, (y1 + y2) / 3); SetExpandosOnElement(pathElem, iGroup, i, centroid); if (DisplayToolTip) { pathElem.MouseEnter += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); pieStart += valueRatio; pieContainer.Children.Add(pathElem); } /*for (var i = 0; i< nPies; ++i) * { * // calculate the pie gradient: * pieContainer.appendChild(pieElems[i]); * }*/ }
internal GaugeChart(ChartType type, ChartModel model) : base(type, model) { }
private void _draw3DPies( Canvas pieContainer, double quadWidth, double quadHeight, int iGroup) { ChartModel model = Model; double[,] yValues = model.YValues; string[] groupLabels = model.GroupLabels; Color[] seriesColors = model.SeriesColors; var pieSize = Math.Min(quadWidth / 2, quadHeight / 2); if (iGroup == -1) { iGroup = 0; } int nPies = yValues.GetUpperBound(1) + 1; double pieTotal = 0; for (int i = 0; i < nPies; ++i) { pieTotal += yValues[iGroup, i]; } string pathXAML = CurrentLookAndFeel.GetPiePathXAML(); Path pathElem; double pieStart = 0; List <UIElement> dataElems = null; bool animate = (AnimationDuration > 0); if (animate) { dataElems = DataElements; } double perspectiveHeight = pieSize / 4; Path[] pieElems = new Path[nPies], ringElems = new Path[nPies], edgeElems = new Path[nPies]; if (perspectiveHeight > _MAX_PERSPECTIVE_HEIGHT) { perspectiveHeight = _MAX_PERSPECTIVE_HEIGHT; } string gradientXAML = CurrentLookAndFeel.GetElementGradientXAML(); TranslateTransform defaultTransform; for (int i = 0; i < nPies; ++i) { double valueRatio = 1 - (yValues[iGroup, i]) / (pieTotal); double arcBeginX, arcBeginY, arcEndX, arcEndY; arcBeginX = pieSize * Math.Cos(pieStart * Math.PI * 2); arcBeginY = pieSize * Math.Sin(pieStart * Math.PI * 2); StringBuilder sb = new StringBuilder(); sb.Append("M0,0L").Append(arcBeginX).Append(",").Append(arcBeginY); arcEndX = pieSize * Math.Cos((pieStart + valueRatio) * Math.PI * 2); arcEndY = pieSize * Math.Sin((pieStart + valueRatio) * Math.PI * 2); if (valueRatio >= .5) { sb.Append(" A").Append(pieSize).Append(",").Append(pieSize).Append(" 1 0 0 "); } else { sb.Append(" A").Append(pieSize).Append(",").Append(pieSize).Append(" 1 1 0 "); } sb.Append(arcEndX).Append(",").Append(arcEndY); sb.Append(" z"); pathElem = CreatePathFromXAMLAndData(pathXAML, sb); if (animate) { dataElems.Add(pathElem); defaultTransform = new TranslateTransform(); defaultTransform.X = defaultTransform.Y = -10000; pathElem.SetValue(Canvas.RenderTransformProperty, defaultTransform); _pieAnimAngles.Add(pieStart + valueRatio / 2); } if (gradientXAML != null) { SetGradientOnElement(pathElem, gradientXAML, seriesColors[i], 0xe5); } else { SetFillOnElement(pathElem, seriesColors[i]); } pathElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[i])); // centroid of the pie triangle Point centroid = new Point((arcBeginX + arcEndX) / 3, (arcBeginY + arcEndY) / 3); SetExpandosOnElement(pathElem, iGroup, i, centroid); if (DisplayToolTip) { pathElem.MouseEnter += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); sb = new StringBuilder(); sb.Append("M").Append(arcBeginX).Append(",").Append(arcBeginY); if (valueRatio >= .5) // major arc { sb.Append(" A").Append(pieSize).Append(",").Append(pieSize).Append(" 1 0 0 "); } else { sb.Append(" A").Append(pieSize).Append(" ").Append(pieSize).Append(" 1 1 0 "); } sb.Append(arcEndX).Append(",").Append(arcEndY); sb.Append(" v").Append(perspectiveHeight); sb.Append(" M").Append(arcEndX).Append(",").Append(arcEndY + perspectiveHeight); if (valueRatio >= .5) // major arc { sb.Append(" A").Append(pieSize).Append(",").Append(pieSize).Append(" 1 0 1 "); } else { sb.Append(" A").Append(pieSize).Append(",").Append(pieSize).Append(" 1 1 1 "); } sb.Append(arcBeginX).Append(",").Append(arcBeginY + perspectiveHeight); sb.Append(" v").Append(-perspectiveHeight); Path pathRingElem = CreatePathFromXAMLAndData(pathXAML, sb); if (gradientXAML != null) { SetGradientOnElement(pathRingElem, gradientXAML, seriesColors[i], 0xe5); } else { SetFillOnElement(pathRingElem, seriesColors[i]); } pathRingElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[i])); sb = new StringBuilder(); sb.Append("M0,0L"); sb.Append(arcBeginX).Append(",").Append(arcBeginY); sb.Append("v").Append(perspectiveHeight); sb.Append("L").Append(0).Append(",").Append(perspectiveHeight); sb.Append("z"); sb.Append("M0,0L"); sb.Append(arcEndX).Append(",").Append(arcEndY); sb.Append("v").Append(perspectiveHeight); sb.Append("L").Append(0).Append(",").Append(perspectiveHeight); sb.Append("z"); Path pathEdgeElem = CreatePathFromXAMLAndData(pathXAML, sb); if (animate) { dataElems.Add(pathRingElem); defaultTransform = new TranslateTransform(); defaultTransform.X = defaultTransform.Y = -10000; pathRingElem.SetValue(Canvas.RenderTransformProperty, defaultTransform); dataElems.Add(pathEdgeElem); defaultTransform = new TranslateTransform(); defaultTransform.X = defaultTransform.Y = -10000; pathEdgeElem.SetValue(Canvas.RenderTransformProperty, defaultTransform); } (pathEdgeElem.Data as PathGeometry).FillRule = FillRule.Nonzero; if (gradientXAML != null) { SetGradientOnElement(pathEdgeElem, gradientXAML, seriesColors[i], 0xe5); } else { SetFillOnElement(pathEdgeElem, seriesColors[i]); } pathEdgeElem.SetValue(Rectangle.StrokeProperty, new SolidColorBrush(seriesColors[i])); if (DisplayToolTip) { pathRingElem.MouseEnter += new MouseEventHandler(ShowToolTip); pathRingElem.MouseLeave += new MouseEventHandler(HideToolTip); pathEdgeElem.MouseEnter += new MouseEventHandler(ShowToolTip); pathEdgeElem.MouseLeave += new MouseEventHandler(HideToolTip); } SetExpandosOnElement(pathRingElem, iGroup, i, centroid); SetExpandosOnElement(pathEdgeElem, iGroup, i, centroid); pieStart += valueRatio; pieElems[i] = pathElem; ringElems[i] = pathRingElem; edgeElems[i] = pathEdgeElem; } UIElementCollection children = pieContainer.Children; // For the top half, edges have preference over rings double totalRatio = 0; for (int i = 0; i < nPies; ++i) { if (totalRatio <= .5) { children.Add(ringElems[i]); } totalRatio += (yValues[iGroup, i]) / (pieTotal); } totalRatio = 0; for (int i = 0; i < nPies; ++i) { if (totalRatio <= .5) { children.Add(edgeElems[i]); } totalRatio += (yValues[iGroup, i]) / (pieTotal); } // For the bottom half, rings have preference over edges totalRatio = 0; for (int i = 0; i < nPies; ++i) { if (totalRatio > .5) { children.Add(edgeElems[i]); } totalRatio += (yValues[iGroup, i]) / (pieTotal); } totalRatio = 0; for (int i = 0; i < nPies; ++i) { if (totalRatio > .5) { children.Add(ringElems[i]); } totalRatio += (yValues[iGroup, i]) / (pieTotal); } for (int i = 0; i < nPies; ++i) { children.Add(pieElems[i]); } }
private void _drawPerspectivePoints() { bool animate = (this.AnimationDuration > 0); double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective; double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight - xOffset); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom - yOffset); LookAndFeel lf = CurrentLookAndFeel; string dotXAML = lf.GetScatterDot3DXAML(); Path dotElem; List <UIElement> dataElems = null; if (animate) { dataElems = DataElements; } ChartModel model = Model; string [] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; string [] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color [] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minYValue = model.MinYValue, maxYValue = model.MaxYValue; int nValues = yValues.GetUpperBound(0) + 1; double[,] xValues = model.XValues; double minXValue = model.MinXValue, maxXValue = model.MaxXValue; double barWidth = (gridWidth / (double)(groupCount - 1)); double gridBottom = gridHeight + marginTop + yOffset; double dx, dy, gridCx = 0, gridCy = 0; string gradientXAML = lf.GetElementGradientXAML(); if (animate) { _cxs = new double[seriesCount * nValues]; _cys = new double[seriesCount * nValues]; gridCx = gridWidth / 2 + marginLeft + xOffset; gridCy = gridHeight / 2 + marginTop; } for (int i = 0; i < seriesCount; ++i) { for (int j = 0; j < nValues; ++j) { dy = gridBottom - gridHeight * (yValues[j, i] - minYValue) / (maxYValue - minYValue); dx = marginLeft + gridWidth * (xValues[j, i] - minXValue) / (maxXValue - minXValue); dotElem = XamlReader.Load(dotXAML) as Path; EllipseGeometry eg = dotElem.Data as EllipseGeometry; if (animate) { dataElems.Add(dotElem); eg.Center = new Point(gridCx, gridCy); // we will use it during animation int cIndex = (i * nValues + j); _cxs[cIndex] = dx; _cys[cIndex] = dy; } else { eg.Center = new Point(dx, dy); } if (gradientXAML != null) { SetGradientOnElement(dotElem, gradientXAML, seriesColors[i], 0xe5); } else { SetFillOnElement(dotElem, seriesColors[i]); } dotElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[i])); SetExpandosOnElement(dotElem, j, i, new Point(dx, dy)); if (DisplayToolTip) { dotElem.MouseEnter += new MouseEventHandler(ShowToolTip); dotElem.MouseLeave += new MouseEventHandler(HideToolTip); } dotElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); //TODO: // Silverlight does not support Filter effects so use another do as a shadow for it. var shadowElem = XamlReader.Load(dotXAML) as Path; eg = shadowElem.Data as EllipseGeometry; if (animate) { dataElems.Add(shadowElem); eg.Center = new Point(gridCx, gridCy); } else { eg.Center = new Point(dx, dy); } shadowElem.Fill = new SolidColorBrush(Color.FromArgb(0x7f, 0x33, 0x33, 0x33)); shadowElem.SetValue(Path.StrokeThicknessProperty, 0.0); TranslateTransform tt = new TranslateTransform(); tt.X = tt.Y = 3; shadowElem.SetValue(UIElement.RenderTransformProperty, tt); ChartCanvas.Children.Add(shadowElem); ChartCanvas.Children.Add(dotElem); } } }
private void _drawPerspectiveAreas(int mod, int rem) { bool animate = (this.AnimationDuration > 0); double xOffset = XOffsetPerspective, yOffset = YOffsetPerspective; double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight - xOffset); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom - yOffset); LookAndFeel lf = CurrentLookAndFeel; string pathXAML = lf.GetAreaPathXAML(); Path pathElem; List <UIElement> dataElems = null; MatrixTransform defaultTransform = null; if (animate) { dataElems = DataElements; } bool isStacked = (Type == ChartType.AREA_STACKED); ChartModel model = Model; string [] groupLabels = model.GroupLabels; int groupCount = groupLabels.Length; string [] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color [] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minValue = model.MinYValue, maxValue = model.MaxYValue; int yValueCount = yValues.GetUpperBound(0) + 1; double barWidth = (gridWidth / (Math.Max(yValueCount, groupCount))), stackBase; double barHeight; double gridBottom = gridHeight + marginTop + yOffset, dx, dy; double[] cumYs = isStacked? new double[yValueCount] : null; if (isStacked) { cumYs = new double[yValueCount]; for (int j = 0; j < yValueCount; ++j) { cumYs[j] = double.NaN; } } string gradientXAML = lf.GetElementGradientXAML(); for (int i = 0; i < seriesCount; ++i) { // for combo charts we draw a bar every once in a mod. if ((mod > 1) && (i % mod) != rem) { continue; } dx = marginLeft + barWidth / 2.0; // If we use non zero min and it is a stacked graph, we need to remove the min for only // the first series. stackBase = (i == 0?minValue:0); StringBuilder sb = new StringBuilder(); for (int j = 0; j < yValueCount; ++j) { barHeight = gridHeight * (yValues[j, i] - stackBase) / (maxValue - minValue); if (isStacked) { if (double.IsNaN(cumYs[j])) { cumYs[j] = gridBottom; } dy = (cumYs[j] -= barHeight); } else { dy = gridBottom - barHeight; } if (j == yValueCount - 1) { break; } sb.Append("M").Append(dx).Append(",").Append(dy); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); if (i == 0 || !isStacked) { sb.Append(" L").Append(dx + xOffset).Append(",").Append(gridHeight + marginTop); } else { sb.Append(" v").Append(barHeight); } sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset); sb.Append(" z"); sb.Append("M").Append(dx).Append(",").Append(dy); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); double nextdy, nextdx = dx + barWidth; if (isStacked) { if (double.IsNaN(cumYs[j + 1])) { cumYs[j + 1] = gridBottom; } nextdy = (cumYs[j + 1] - gridHeight * (yValues[j + 1, i] - stackBase) / (maxValue - minValue)); } else { nextdy = gridBottom - gridHeight * (yValues[j + 1, i] - minValue) / (maxValue - minValue); } sb.Append(" L").Append(nextdx + xOffset).Append(",").Append(nextdy - yOffset); sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset); sb.Append(" L").Append(dx).Append(",").Append(dy); sb.Append(" M").Append(nextdx).Append(",").Append(nextdy); sb.Append(" l").Append(xOffset).Append(",").Append(-yOffset); if (i == 0 || !isStacked) { sb.Append(" L").Append(nextdx + xOffset).Append(",").Append(gridHeight + marginTop); } else { sb.Append(" L").Append(nextdx + xOffset).Append(",").Append(cumYs[j + 1] - yOffset); } sb.Append(" l").Append(-xOffset).Append(",").Append(yOffset); sb.Append(" L").Append(nextdx).Append(",").Append(nextdy); sb.Append(" M").Append(dx).Append(",").Append(dy); sb.Append(" L").Append(nextdx).Append(",").Append(nextdy); if (i == 0 || !isStacked) { sb.Append(" L").Append(nextdx).Append(",").Append(gridBottom); sb.Append(" L").Append(dx).Append(",").Append(gridBottom); } else { sb.Append(" L").Append(nextdx).Append(",").Append(cumYs[j + 1]); sb.Append(" L").Append(dx).Append(",").Append( cumYs[j] + gridHeight * (yValues[j, i] - stackBase) / (maxValue - minValue)); } sb.Append(" L").Append(dx).Append(",").Append(dy); dx += barWidth; } pathElem = CreatePathFromXAMLAndData(pathXAML, sb); SetExpandosOnElement(pathElem, -1, i, new Point()); if (DisplayToolTip) { pathElem.MouseMove += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); if (gradientXAML != null) { SetGradientOnElement(pathElem, gradientXAML, seriesColors[i], 0x7F); } else { SetFillOnElement(pathElem, seriesColors[i]); } pathElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[i])); (pathElem.Data as PathGeometry).FillRule = FillRule.Nonzero; if (animate) { dataElems.Add(pathElem); defaultTransform = new MatrixTransform(); Matrix m = new Matrix(); m.M11 = 0.0; defaultTransform.Matrix = m; pathElem.SetValue(UIElement.RenderTransformProperty, defaultTransform); } ChartCanvas.Children.Add(pathElem); } }
public HorizontalBarChart(ChartType type, ChartModel model) : base(type, model) { }
private void _displayToolTips( object sender, MouseEventArgs e, double[] seriesValues, int [] seriesIndices ) { ChartModel model = Model; string[] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color[] seriesColors = model.SeriesColors; int tooltipCount = seriesIndices.Length;; Point pt = e.GetPosition(ChartCanvas); double dx, dy; if (_tooltips == null) { _tooltips = new Canvas[seriesCount]; } for (int i = 0; i < tooltipCount; ++i) { int seriesIndex = seriesIndices[i]; Canvas toolTip = _tooltips[seriesIndex]; bool resizeOnInit = false; if (toolTip == null) { toolTip = XamlReader.Load(CurrentLookAndFeel.GetTooltipXAML()) as Canvas; ChartCanvas.Children.Add(toolTip); _tooltips[seriesIndex] = toolTip; resizeOnInit = true; } toolTip.Visibility = Visibility.Visible; Path circleElem = toolTip.Children[0] as Path; Path boundingRectElem = toolTip.Children[1] as Path; //append all the series values as labels TextBlock textElem = toolTip.Children[2] as TextBlock; int textElemCount = seriesValues.Length; textElem.Text = seriesLabels[seriesIndex] + ": " + seriesValues[i].ToString(Format); double rectWidth = textElem.ActualWidth; RectangleGeometry rg = boundingRectElem.Data as RectangleGeometry; Rect rect = rg.Rect; // Initially the template tooltip has an extra text node if (resizeOnInit) { dy = textElem.ActualHeight; rg.Rect = new Rect(rect.X, rect.Y, rect.Width, rect.Height - dy); textElem = toolTip.Children[3] as TextBlock; textElem.Text = ""; } rectWidth += 2 * _TEXT_MARGIN; rect = rg.Rect; rg.Rect = new Rect(rect.X, rect.Y, rectWidth, rect.Height); EllipseGeometry eg = circleElem.Data as EllipseGeometry; dx = pt.X; dy = _seriesYs[i] - rect.Height; if (IsPerspective) { dy -= YOffsetPerspective / 2.0; } double cx, cy; if (dx + rectWidth > ChartCanvas.Width) { dx -= rectWidth; cx = rectWidth; } else { cx = 0; } if (dy - rect.Height < 0) { dy += rect.Height; cy = 0; } else { cy = rect.Height; } eg.Center = new Point(cx, cy); boundingRectElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[seriesIndex])); circleElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[seriesIndex])); TranslateTransform tTrans = new TranslateTransform(); tTrans.X = dx; tTrans.Y = dy; toolTip.RenderTransform = tTrans; } }
private void _drawXYValues() { bool animate = (this.AnimationDuration > 0); double marginLeft = MarginLeft, marginTop = MarginTop; double marginRight = MarginRight, marginBottom = MarginBottom; double gridWidth = (ChartCanvas.Width - marginLeft - marginRight); double gridHeight = (ChartCanvas.Height - marginTop - marginBottom); LookAndFeel lf = CurrentLookAndFeel; string pathXAML = lf.GetLinePathXAML(); Path pathElem; List <UIElement> dataElems = null; if (animate) { dataElems = DataElements; } ChartModel model = Model; string[] seriesLabels = model.SeriesLabels; int seriesCount = seriesLabels.Length; Color[] seriesColors = model.SeriesColors; double[,] yValues = model.YValues; double minYValue = model.MinYValue, maxYValue = model.MaxYValue; int nValues = yValues.GetUpperBound(0) + 1; double[,] xValues = model.XValues; double minXValue = model.MinXValue, maxXValue = model.MaxXValue; double dx, dy; MatrixTransform defaultTransform; for (int i = 0; i < seriesCount; ++i) { StringBuilder sb = new StringBuilder(); dx = marginLeft; dy = gridHeight + marginTop; for (int j = 0; j < nValues; ++j) { dy = gridHeight + marginTop - gridHeight * (yValues[j, i] - minYValue) / (maxYValue - minYValue); dx = marginLeft + gridWidth * (xValues[j, i] - minXValue) / (maxXValue - minXValue); if (j == 0) { sb.Append("M").Append(dx).Append(",").Append(dy); } else { sb.Append(" L").Append(dx).Append(",").Append(dy); } } pathElem = CreatePathFromXAMLAndData(pathXAML, sb); if (animate) { dataElems.Add(pathElem); defaultTransform = new MatrixTransform(); Matrix m = new Matrix(); m.M11 = 0.0; defaultTransform.Matrix = m; pathElem.SetValue(UIElement.RenderTransformProperty, defaultTransform); } SetExpandosOnElement(pathElem, -1, i, new Point()); if (DisplayToolTip) { pathElem.MouseMove += new MouseEventHandler(ShowToolTip); pathElem.MouseLeave += new MouseEventHandler(HideToolTip); } pathElem.MouseLeftButtonUp += new MouseButtonEventHandler(ChartDataClicked); pathElem.SetValue(Path.StrokeProperty, new SolidColorBrush(seriesColors[i])); ChartCanvas.Children.Add(pathElem); } }