public RichTextArea(string id, Vector2 position, Size size, string text, TextStyle style, BorderStyle borderStyle, ColorArray colorArray) : base(id, position, size, Shape.Rectangle, borderStyle, Shapes.ShadeTopToBottom, colorArray) { Vector2 labelPosition = new Vector2(DefaultLabelPaddingX, DefaultLabelPaddingY); textMarkup = text; textStyle = style; LabelFormatter lF = new LabelFormatter(id, textStyle, labelPosition, new Size(size.Width - 2 * DefaultLabelPaddingX, size.Height - DefaultLabelPaddingY), textMarkup); page = lF.FormattedLabelCollection; foreach (Label l in page.LabelCollection) { if (l != null) { Add(l); } } page.Align(); }
/// <summary> /// Layer's main piece of code that does the drawing. This method calculates and /// populates a scene graph with various primitive that constitue the chart. /// </summary> /// <param name="scene">Collection of Scene items (primitives) to hold items that draw chart.</param> public void FillSceneGraph(SceneGraph scene) { //Draw the axes, use the settings from the y axis properties. AxisAppearance YApp = (AxisAppearance)this.ChartComponent.GetChartAppearance(ChartAppearanceTypes.AxisY); // Check if appearance and Y-axis appearance are defined. if (_Appearance != null && YApp != null) { #region Initialization // initilize the variable. // Minimum value a needle can have. double min = 0; // Maximum value a needle can have. double max = 100; // Tick increments. double delta = 10; // Check to see if the Gauge should assume size and layout automatically // centering the dial and assuming available width as its size. if (this._Appearance.Layout == DialLayout.Automatic) { this._Appearance.Radius = Math.Min(this.innerBounds.Width / 3, this.innerBounds.Height / 3); this._Appearance.Center = new Point(this.innerBounds.X + this.innerBounds.Width / 2, this.innerBounds.Y + this.innerBounds.Height / 2); } // check for axis settings // If cutom rage is specified use custom range. if (YApp.RangeType == AxisRangeType.Custom) { min = YApp.RangeMin; max = YApp.RangeMax; } else { // Automatic: add up the specified sections. if (this._Appearance.Sections.Count > 0) { min = 0; max = 0; foreach (GaugeSection sec in this._Appearance.Sections) { max += sec.Value; } } } // Assume and calculate the default increment. delta = (max - min) / 10; // check for y-axis appearance for specified data interval. if (YApp.TickmarkStyle == AxisTickStyle.DataInterval) { // Actual value is specified. delta = YApp.TickmarkInterval; } else { // Convert the percentage value in actual value. delta = (max - min) * YApp.TickmarkPercentage / 100; } // set up ruler with value. This will be used for measurement purposes. _Ruler.Maximum = max; _Ruler.Minimum = min; // Check the direction of the dial ticks. if (this.Appearance.Direction == Direction.RightToLeft) { _Ruler.MapMinimum = _Appearance.StartAngle; _Ruler.MapMaximum = _Appearance.EndAngle; } else { _Ruler.MapMinimum = _Appearance.EndAngle; _Ruler.MapMaximum = _Appearance.StartAngle; } // copy scoll-scale. _Ruler.Scale = YApp.ScrollScale.Scale; _Ruler.Scroll = YApp.ScrollScale.Scroll; #endregion #region Draw dial and sections // start from the minimum double d_i = (double)_Ruler.WindowMinimum; // calculate various radii. int r1 = this._Appearance.TickStart * this._Appearance.Radius / 100; int r2 = this._Appearance.TickEnd * this._Appearance.Radius / 100; int r3 = this._Appearance.TextLoc * this._Appearance.Radius / 100; // draw dial or background. Ellipse dial = new Ellipse(this._Appearance.Center, this._Appearance.Radius); dial.PE = this.Appearance.DialPE; // add dial background. scene.Add(dial); // draw the sections // variable to hold present value. double presentVal = 0; // start the section from the window minimum. double lastVal = (double)_Ruler.WindowMinimum; // foreach section, draw a section. foreach (GaugeSection sec in this._Appearance.Sections) { presentVal = lastVal + sec.Value; // section start angle. int ang0 = -(int)_Ruler.Map(lastVal); // section end angle. int ang1 = -(int)_Ruler.Map(presentVal); // create the wedge Wedge w = new Wedge(this._Appearance.Center, sec.EndWidth * this._Appearance.Radius / 100, ang0, (ang1 - ang0)); w.PE = sec.PE; w.RadiusInner = Math.Max(0, Math.Min(w.Radius - 1, sec.StartWidth * this._Appearance.Radius / 100)); scene.Add(w); lastVal = presentVal; } #endregion #region Draw axis' tick marks on dial // sanity check for increment. Without this it will go into infinite loop. if (delta < 2 * double.Epsilon) { delta = 5 * double.Epsilon; } // loop thru and add the items. while (d_i < (double)_Ruler.WindowMaximum + 2 * double.Epsilon + delta) { // convert the tickmark value to angle int ang = (int)_Ruler.Map(d_i); // see if major grid lines are visible. if (YApp.MajorGridLines.Visible) { // Convert polar co-ordinates into cartiesian. // In simple words: Convert a pair of (radius, angle) in a point (x and y). Point p1 = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, r1, -Geometry.DegreeToRadian(ang)); Point p2 = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, r2, -Geometry.DegreeToRadian(ang)); // Draw the line for tick marks. Use Y-axis's properties to color and style it. Line l = new Line(p1, p2); l.PE.Stroke = YApp.MajorGridLines.Color; l.PE.StrokeOpacity = YApp.MajorGridLines.Color.A; l.lineStyle.DrawStyle = YApp.MajorGridLines.DrawStyle; l.PE.StrokeWidth = YApp.MajorGridLines.Thickness; // add to scene. scene.Add(l); } // see if minor grid lines are visible. If yes draw them half // a tick far from major grid line. It will use Y-axis's minor // grid lines appearance for color and style. if (YApp.MinorGridLines.Visible) { if (d_i + delta / 2 < (double)_Ruler.WindowMaximum) { // convert the tickmark value to angle int ang1 = (int)_Ruler.Map(d_i + delta / 2); int tfp = Math.Abs((r2 - r1) / 4); // Convert a pair of (radius, angle) in a point (x and y). Point p1 = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, r1 + tfp, -Geometry.DegreeToRadian(ang1)); Point p2 = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, r2 - tfp, -Geometry.DegreeToRadian(ang1)); // draw a minor tick line Line l = new Line(p1, p2); l.PE.Stroke = YApp.MinorGridLines.Color; l.PE.StrokeOpacity = YApp.MinorGridLines.Color.A; l.lineStyle.DrawStyle = YApp.MinorGridLines.DrawStyle; l.PE.StrokeWidth = YApp.MinorGridLines.Thickness; // add to scene. scene.Add(l); } } // see if labels are visible. if (YApp.Labels.Visible) { // Draw the labels: Convert the angle and radius into point location for the label. Point p3 = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, r3, -Geometry.DegreeToRadian(ang)); _Labels["DATA_VALUE"] = d_i; // Use the label formatter and use Y-axis label format. Text t = new Text(p3, LabelFormatter.replaceKeywords(_Labels, YApp.Labels.ItemFormatString), YApp.Labels.LabelStyle.Copy()); t.labelStyle.VerticalAlign = StringAlignment.Center; t.labelStyle.HorizontalAlign = StringAlignment.Center; // Use custom orienation as we need to rotate them to // place them on angular axis. t.labelStyle.Orientation = TextOrientation.Custom; // rotate with respect to present tick angle. t.labelStyle.RotationAngle = ang - 90; // add to scene. scene.Add(t); } // increment current value of tick by the data interval: delta. d_i += delta; } // See if axis line is visible. if (YApp.Visible) { // create new line style LineStyle ls = new LineStyle(); // use y-axis's draw style. ls.DrawStyle = YApp.LineDrawStyle; // draw an arc that looks takes place of axis line. Arc el = new Arc(this._Appearance.Center, (r1 + r2) / 2, (float)this._Appearance.StartAngle, -(float)Math.Abs(this._Appearance.EndAngle - this._Appearance.StartAngle), ls); // use the axes line's color and thickness. el.PE.Stroke = YApp.LineColor; el.PE.StrokeOpacity = YApp.LineColor.A; el.PE.StrokeWidth = YApp.LineThickness; // add to scene. scene.Add(el); } #endregion #region Draw needles // sort needles according to needle length. shortest comes on the top. double[] ar = new Double[this.Appearance.Needles.Count]; for (int i = 0; i < this.Appearance.Needles.Count; i++) { // store the length of needle in temporary array. ar[i] = this.Appearance.Needles[i].Length; } // sort the order. This function takes the length of // needle array and get the sorted order. int[] order = null; if (ar.Length > 0) { order = MiscFunctions.GetSortedOrderDouble(ar); } // draw the needles on the dials for (int i = 0; i < this.Appearance.Needles.Count; i++) { // get n-th needle. Needle nd = this.Appearance.Needles[order[i]]; // depending upon needle's present value find out the // angle at which it should be inclined. int theta_i = (int)_Ruler.Map(nd.Value); // convert, angle of needle and its length into a point location. Point p = Infragistics.UltraChart.Core.Util.Geometry.AngularToCartesian(this._Appearance.Center, nd.Length * this._Appearance.Radius / 100, Geometry.DegreeToRadian(-theta_i)); // draw a line from the center of dial to location of needle's head. Line l = new Line(this._Appearance.Center, p); l.lineStyle.EndStyle = LineCapStyle.ArrowAnchor; l.lineStyle.StartStyle = LineCapStyle.RoundAnchor; // attach the paint element from needle to the line primitive. l.PE = nd.PE; // add to scene. scene.Add(l); } #endregion } }
/// <summary> /// Main flow of the render pipeline. /// </summary> /// <param name="sc"></param> /// <param name="ist"></param> /// <param name="recycler"></param> void ElementPipeline(SelectorContext sc, ItemState ist, Recycler <FrameworkElement, ItemState> recycler) { sc.SetTick(ist.index); var createit = true; if (LabelSelector != null) { var ox = LabelSelector.Convert(sc, typeof(bool), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (ox is bool bx) { createit = bx; } else { createit = ox != null; } } if (!createit) { return; } var current = recycler.Next(ist); if (current == null) { return; } if (!current.Item1) { // recycled: restore binding if we are using a LabelFormatter if (LabelFormatter != null && LabelStyle != null) { BindTo(this, nameof(LabelStyle), current.Item2, FrameworkElement.StyleProperty); } } // default text var text = ist.label == null ? String.Empty : (String.IsNullOrEmpty(LabelFormatString) ? ist.label.ToString() : String.Format(LabelFormatString, ist.label) ); if (LabelFormatter != null) { // call for Style, String override var format = LabelFormatter.Convert(sc, typeof(Tuple <Style, String>), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (format is Tuple <Style, String> ovx) { if (ovx.Item1 != null) { current.Item2.Style = ovx.Item1; } if (ovx.Item2 != null) { text = ovx.Item2; } } } // back-fill values var shim = new TextShim() { Text = text }; current.Item2.DataContext = shim; BindTo(shim, nameof(Visibility), current.Item2, UIElement.VisibilityProperty); ist.element = current.Item2; sc.Generated(ist); }
void DoTickLabels(IChartRenderContext icrc) { var tc = new TickCalculator(Minimum, Maximum); _trace.Verbose($"grid range:{tc.Range} tintv:{tc.TickInterval}"); // TODO may want to include the LabelStyle's padding if defined var padding = AxisLineThickness + 2 * AxisMargin; var tbr = new Recycler <FrameworkElement, ItemState>(TickLabels.Select(tl => tl.tb), (ist) => { var fe = CreateElement(ist); fe.Width = icrc.Area.Width - padding; if (fe is TextBlock tbb) { tbb.Padding = Side == Side.Right ? new Thickness(padding, 0, 0, 0) : new Thickness(0, 0, padding, 0); } return(fe); }); var itemstate = new List <ItemState>(); // materialize the ticks var lx = tc.GetTicks().ToArray(); var sc = new ValueAxisSelectorContext(this, icrc.Area, lx, tc.TickInterval); for (int ix = 0; ix < lx.Length; ix++) { //_trace.Verbose($"grid vx:{tick}"); sc.SetTick(ix); var createit = true; if (LabelSelector != null) { // ask the label selector var ox = LabelSelector.Convert(sc, typeof(bool), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (ox is bool bx) { createit = bx; } else { createit = ox != null; } } if (!createit) { continue; } var current = tbr.Next(null); var tick = lx[ix]; if (!current.Item1) { // restore binding if we are using a LabelFormatter if (LabelFormatter != null && LabelStyle != null) { BindTo(this, nameof(LabelStyle), current.Item2, FrameworkElement.StyleProperty); } } // default text var text = tick.Value.ToString(String.IsNullOrEmpty(LabelFormatString) ? "G" : LabelFormatString); if (LabelFormatter != null) { // call for Style, String override var format = LabelFormatter.Convert(sc, typeof(Tuple <Style, String>), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (format is Tuple <Style, String> ovx) { if (ovx.Item1 != null) { current.Item2.Style = ovx.Item1; } if (ovx.Item2 != null) { text = ovx.Item2; } } } var shim = new TextShim() { Text = text }; current.Item2.DataContext = shim; BindTo(shim, nameof(Visibility), current.Item2, UIElement.VisibilityProperty); var state = new ItemState() { tb = current.Item2, tick = tick }; state.SetLocation(icrc.Area.Left, tick.Value); sc.Generated(tick); itemstate.Add(state); } // VT and internal bookkeeping TickLabels = itemstate; Layer.Remove(tbr.Unused); Layer.Add(tbr.Created); foreach (var xx in TickLabels) { // force it to measure; needed for Transforms xx.tb.Measure(icrc.Dimensions); } }