/* Copyright (C) 2008 Webyog Softworks Private Limited This file is a part of Visifire Charts. Visifire is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with Visifire Charts. If not, see . If GPL is not suitable for your products or company, Webyog provides Visifire under a flexible commercial license designed to meet your specific usage and distribution requirements. If you have already obtained a commercial license from Webyog, you can use this file under those license terms. */ #if WPF using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Media.Animation; #else using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; using System.Collections.Generic; #endif using Visifire.Commons; using System.Windows.Shapes; namespace Visifire.Charts { /// /// Visifire.Charts.StockChart class /// internal class StockChart { #region Public Methods #endregion #region Public Properties #endregion #region Public Events And Delegates #endregion #region Protected Methods #endregion #region Internal Properties #endregion #region Private Properties #endregion #region Private Delegates #endregion #region Private Methods #endregion #region Internal Methods /// /// Recalculate and apply new brush /// /// Shape reference /// New Brush /// Whether lighting is enabled /// New Calculated Brush internal static Brush ReCalculateAndApplyTheNewBrush(Shape shape, Brush newBrush, Boolean isLightingEnabled) { shape.Stroke = ((Boolean)isLightingEnabled) ? Graphics.GetLightingEnabledBrush(newBrush, "Linear", null) : newBrush; return shape.Stroke; } /// /// Get visual object for point chart /// /// Width of the charat /// Height of the charat /// plotDetails /// List of DataSeries /// Chart /// Plank depth /// Whether animation is enabled /// Point chart canvas internal static Canvas GetVisualObjectForStockChart(Double width, Double height, PlotDetails plotDetails, List seriesList, Chart chart, Double plankDepth, bool animationEnabled) { if (Double.IsNaN(width) || Double.IsNaN(height) || width <= 0 || height <= 0) return null; Canvas visual = new Canvas() { Width = width, Height = height }; Canvas labelCanvas = new Canvas() { Width = width, Height = height }; Double depth3d = plankDepth / (plotDetails.Layer3DCount == 0 ? 1 : plotDetails.Layer3DCount) * (chart.View3D ? 1 : 0); Double visualOffset = depth3d * (plotDetails.SeriesDrawingIndex[seriesList[0]] + 1 - (plotDetails.Layer3DCount == 0 ? 0 : 1)); visual.SetValue(Canvas.TopProperty, visualOffset); visual.SetValue(Canvas.LeftProperty, -visualOffset); Double highY = 0, lowY = 0, openY = 0, closeY = 0; Double animationBeginTime = 0; DataSeries _tempDataSeries = null; // Calculate width of a DataPoint _dataPointWidth = CandleStick.CalculateDataPointWidth(width, height, chart); foreach (DataSeries series in seriesList) { if (series.Enabled == false) continue; Canvas seriesCanvas = new Canvas() { Width = width, Height = height }; _tempDataSeries = series; PlotGroup plotGroup = series.PlotGroup; foreach (DataPoint dataPoint in series.InternalDataPoints) { if (dataPoint.YValues == null || (dataPoint.Enabled == false)) continue; // Creating ElementData for Tag ElementData tagElement = new ElementData() { Element = dataPoint }; CandleStick.SetDataPointValues(dataPoint, ref highY, ref lowY, ref openY, ref closeY); // Calculate required pixel positions Double xPositionOfDataPoint = Graphics.ValueToPixelPosition(0, width, (Double)plotGroup.AxisX.InternalAxisMinimum, (Double)plotGroup.AxisX.InternalAxisMaximum, dataPoint.InternalXValue); openY = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, openY); closeY = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, closeY); highY = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, highY); lowY = Graphics.ValueToPixelPosition(height, 0, (Double)plotGroup.AxisY.InternalAxisMinimum, (Double)plotGroup.AxisY.InternalAxisMaximum, lowY); Double dataPointTop = (lowY < highY) ? lowY : highY; openY = openY - dataPointTop; closeY = closeY - dataPointTop; // Create DataPoint Visual Canvas dataPointVisual = new Canvas() { Width = _dataPointWidth, Height = Math.Abs(lowY - highY) }; // Set DataPoint Visual position dataPointVisual.SetValue(Canvas.TopProperty, dataPointTop); dataPointVisual.SetValue(Canvas.LeftProperty, xPositionOfDataPoint - _dataPointWidth / 2); // Create High and Low Line Line highLow = new Line() { Tag = tagElement, X1 = dataPointVisual.Width / 2, X2 = dataPointVisual.Width / 2, Y1 = 0, Y2 = dataPointVisual.Height, StrokeThickness = (Double) dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; ReCalculateAndApplyTheNewBrush(highLow, dataPoint.Color, (Boolean) dataPoint.LightingEnabled); // Create Open Line Line open = new Line() { Tag = tagElement, X1 = 0, X2 = dataPointVisual.Width / 2, Y1 = openY, Y2 = openY, Stroke = highLow.Stroke, StrokeThickness = (Double)dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; // Create Close Line Line close = new Line() { Tag = tagElement, X1 = dataPointVisual.Width / 2, X2 = dataPointVisual.Width, Y1 = closeY, Y2 = closeY, Stroke = highLow.Stroke, StrokeThickness = (Double)dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; #region Apply Shadow if (dataPoint.ShadowEnabled == true) { // Create High and Low Line Line highLowShadow = new Line() { IsHitTestVisible = false, X1 = dataPointVisual.Width / 2 + CandleStick._shadowDepth, X2 = dataPointVisual.Width / 2 + CandleStick._shadowDepth, Y1 = 0 + CandleStick._shadowDepth, Y2 = dataPointVisual.Height + CandleStick._shadowDepth, Stroke = CandleStick._shadowColor, StrokeThickness = (Double)dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; // Create Open Line Line openShadowLine = new Line() { IsHitTestVisible = false, X1 = 0 + CandleStick._shadowDepth, X2 = dataPointVisual.Width / 2 + CandleStick._shadowDepth, Y1 = openY + CandleStick._shadowDepth, Y2 = openY + CandleStick._shadowDepth, Stroke = CandleStick._shadowColor, StrokeThickness = (Double)dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; // Create Close Line Line closeShadowLine = new Line() { IsHitTestVisible = false, X1 = dataPointVisual.Width / 2 + CandleStick._shadowDepth, X2 = dataPointVisual.Width + CandleStick._shadowDepth, Y1 = closeY + CandleStick._shadowDepth, Y2 = closeY + CandleStick._shadowDepth, Stroke = CandleStick._shadowColor, StrokeThickness = (Double)dataPoint.InternalBorderThickness.Left, StrokeDashArray = Graphics.LineStyleToStrokeDashArray(dataPoint.BorderStyle.ToString()) }; // Add shadows dataPointVisual.Children.Add(highLowShadow); dataPointVisual.Children.Add(openShadowLine); dataPointVisual.Children.Add(closeShadowLine); } #endregion if (highLow.StrokeThickness > _dataPointWidth / 2) highLow.StrokeThickness = _dataPointWidth / 2; else if (highLow.StrokeThickness > _dataPointWidth) highLow.StrokeThickness = _dataPointWidth; // Compose DataPoint faces, visual components and visual parts dataPoint.Faces = new Faces(); dataPoint.Faces.Parts = new List(); // Add parts dataPoint.Faces.Parts.Add(highLow); dataPoint.Faces.Parts.Add(open); dataPoint.Faces.Parts.Add(close); // Add VisualComponents dataPoint.Faces.VisualComponents.Add(highLow); dataPoint.Faces.VisualComponents.Add(open); dataPoint.Faces.VisualComponents.Add(close); // Add Border elements dataPoint.Faces.BorderElements.Add(highLow); dataPoint.Faces.BorderElements.Add(open); dataPoint.Faces.BorderElements.Add(close); // Add VisualComponents to visual dataPointVisual.Children.Add(highLow); dataPointVisual.Children.Add(open); dataPointVisual.Children.Add(close); dataPoint.Faces.Visual = dataPointVisual; seriesCanvas.Children.Add(dataPointVisual); // Place label for the DataPoint CandleStick.PlaceLabel(visual, labelCanvas, dataPoint); } // Apply animation to series if (animationEnabled) { if (_tempDataSeries.Storyboard == null) _tempDataSeries.Storyboard = new Storyboard(); _tempDataSeries.Storyboard = AnimationHelper.ApplyOpacityAnimation(seriesCanvas, _tempDataSeries, _tempDataSeries.Storyboard, animationBeginTime, 1, 1); animationBeginTime += 0.5; } visual.Children.Add(seriesCanvas); } // Label animation if (animationEnabled && _tempDataSeries != null) _tempDataSeries.Storyboard = AnimationHelper.ApplyOpacityAnimation(labelCanvas, _tempDataSeries, _tempDataSeries.Storyboard, animationBeginTime, 1, 1); visual.Children.Add(labelCanvas); RectangleGeometry clipRectangle = new RectangleGeometry(); clipRectangle.Rect = new Rect(0, -chart.ChartArea.PLANK_DEPTH, width + chart.ChartArea.PLANK_OFFSET, height + chart.ChartArea.PLANK_DEPTH); visual.Clip = clipRectangle; return visual; } #endregion #region Internal Events And Delegates #endregion #region Data private static Double _dataPointWidth; #endregion } }