void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return;
            }
            var recycler = new Recycler <Path, ItemState <Path> >(CreatePath);
            var reproc   = IncrementalAdd <ItemState <Path> >(startAt, items, ItemState, (ix, item) => {
                var valuey = BindPaths.ValueFor(item);
                // short-circuit if it's NaN
                if (double.IsNaN(valuey))
                {
                    return(null);
                }
                var valuex = BindPaths.CategoryFor(item, ix);
                // add requested item
                var istate = ElementPipeline(ix, valuex, valuey, item, recycler, BindPaths);
                return(istate);
            }, (rpc, istate) => {
                istate.Shift(rpc, BindPaths, CategoryAxis, null);
                // NO geometry update; done in later stages of render pipeline
            });

            ReconfigureLimits();
            // finish up
            Layer.Add(recycler.Created);
            Dirty = false;
            RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc);
        }
Esempio n. 2
0
        void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return;
            }
            var recycler = new Recycler <Path, SeriesItemState>(new List <Path>(), CreatePath);
            var reproc   = IncrementalAdd <SeriesItemState>(startAt, items, ItemState, (ix, item) => {
                var valuex = BindPaths.CategoryFor(item, ix);
                // add requested item
                var istate = ElementPipeline(ix, valuex, item, recycler, BindPaths);
                return(istate);
            }, (rpc, istate) => {
                istate.Shift(rpc, BindPaths, CategoryAxis, UpdateGeometry);
            });

            ReconfigureLimits();
            // finish up
            Layer.Add(recycler.Created);
            Dirty = false;
            RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc);
        }
Esempio n. 3
0
        ItemState CreateSubtick(IChartRenderContext icrc, Recycler <Path, ItemState> recycler, SubtickState tick)
        {
            if (tick.Value <= ValueAxis.Minimum || tick.Value >= ValueAxis.Maximum)
            {
                return(null);
            }
            var state = new ItemState()
            {
                Tick = tick
            };
            var current = recycler.Next(state);

            if (!current.Item1)
            {
                // restore binding
                if (MinorGridPathStyle != null)
                {
                    BindTo(this, nameof(MinorGridPathStyle), current.Item2, FrameworkElement.StyleProperty);
                    TransferFromStyle(current.Item2, MinorGridPathStyle);
                }
                else if (PathStyle != null)
                {
                    BindTo(this, nameof(PathStyle), current.Item2, FrameworkElement.StyleProperty);
                    TransferFromStyle(current.Item2, PathStyle);
                }
            }
            state.Element = current.Item2;
            ApplyBinding(this, nameof(Visibility), state.Element, UIElement.VisibilityProperty);
            state.SetLocation(icrc.Area.Left, tick.Value);
            return(state);
        }
Esempio n. 4
0
        void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items)
        {
            if (CategoryAxis == null || ValueAxis == null)
            {
                return;
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return;
            }
            var recycler = new Recycler <Path, ItemState <Path> >(new List <Path>(), CreatePath);
            var reproc   = IncrementalAdd <ItemState <Path> >(startAt, items, ItemState, (ix, item) => {
                var valueO = BindPaths.OpenFor(item);
                var valueH = BindPaths.HighFor(item);
                var valueL = BindPaths.LowFor(item);
                var valueC = BindPaths.CloseFor(item);
                // short-circuit if it's NaN
                if (double.IsNaN(valueO) || double.IsNaN(valueH) || double.IsNaN(valueL) || double.IsNaN(valueC))
                {
                    return(null);
                }
                var valuex = BindPaths.CategoryFor(item, ix);
                // add requested item
                var istate = ElementPipeline(ix, valuex, valueO, valueH, valueL, valueC, item, recycler, BindPaths.bvl);
                return(istate);
            }, (rpc, istate) => {
                istate.Shift(rpc, BindPaths, CategoryAxis, UpdateGeometry);
            });

            ReconfigureLimits();
            // finish up
            Layer.Add(recycler.Created);
            Dirty = false;
            RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc);
        }
Esempio n. 5
0
        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="state">Starting state; SHOULD be empty.</param>
        /// <param name="rc">The recycler.</param>
        /// <param name="evs">Evaluators.</param>
        internal RenderState_ValueAndLabel(List <SIS> state, Recycler <EL, SIS> rc, Evaluators evs) : base(state, rc)
        {
#pragma warning disable IDE0016 // Use 'throw' expression
            if (evs == null)
            {
                throw new ArgumentNullException(nameof(evs));
            }
            if (evs.by == null)
            {
                throw new ArgumentNullException(nameof(evs.by));
            }
#pragma warning restore IDE0016 // Use 'throw' expression
            this.evs = evs;
        }
        object IDataSourceRenderer.Preamble(IChartRenderContext icrc)
        {
            if (CategoryAxis1 == null || CategoryAxis2 == null)
            {
                return(null);
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return(null);
            }
            ResetLimits();
            var paths    = ItemState.Select(ms => ms.Element).Where(el => el != null);
            var recycler = new Recycler <Path, ItemState <Path> >(paths, CreatePath);

            return(new RenderState_Heatmap <ItemState <Path>, Path>(new List <ItemState <Path> >(), recycler, BindPaths));
        }
Esempio n. 7
0
        object IDataSourceRenderer.Preamble(IChartRenderContext icrc)
        {
            if (ValueAxis == null || CategoryAxis == null)
            {
                return(null);
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return(null);
            }
            ResetLimits();
            var paths    = ItemState.Select(ms => ms.Elements).SelectMany(el => el).Select(el => el.Item2);
            var recycler = new Recycler <Path, SeriesItemState>(paths, CreatePath);

            return(new State(new List <SeriesItemState>(), recycler, BindPaths));
        }
Esempio n. 8
0
        object IDataSourceRenderer.Preamble(IChartRenderContext icrc)
        {
            if (ValueAxis == null || CategoryAxis == null)
            {
                return(null);
            }
            if (BindPaths == null || !BindPaths.IsValid)
            {
                return(null);
            }
            ResetLimits();
            var paths    = ItemState.Select(ms => ms.Element);
            var recycler = new Recycler <Image, ItemState <Image> >(paths, CreateElement);

            return(new RenderState_ValueAndLabel <ItemState <Image>, Image>(new List <ItemState <Image> >(), recycler, BindPaths));
        }
        object IDataSourceRenderer.Preamble(IChartRenderContext icrc)
        {
            if (String.IsNullOrEmpty(ValuePath))
            {
                return(null);
            }
            var by       = new BindingEvaluator(ValuePath);
            var paths    = ItemState.Select(ms => ms.Element);
            var recycler = new Recycler <Path, ItemState <Path> >(paths, CreatePath);

            Generator.Reset();
            return(new State(new List <ItemState <Path> >(), recycler,
                             null,
                             !String.IsNullOrEmpty(ValueLabelPath) ? new BindingEvaluator(ValueLabelPath) : null,
                             by,
                             !String.IsNullOrEmpty(ValueLabelPath) ? new BindingEvaluator(ValueLabelPath) : null
                             ));
        }
Esempio n. 10
0
        /// <summary>
        /// Create the next series state.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="valuex"></param>
        /// <param name="item"></param>
        /// <param name="recycler"></param>
        /// <param name="evs"></param>
        /// <returns>New instance or NULL.</returns>
        SeriesItemState ElementPipeline(int index, double valuex, object item, Recycler <Path, SeriesItemState> recycler, Evaluators evs)
        {
            var leftx  = CategoryAxis.For(valuex);
            var barx   = BarOffset;
            var rightx = barx + BarWidth;
            var sis    = evs.byl == null ? new SeriesItemState(index, leftx, BarOffset) : new SeriesItemState_Custom(index, leftx, BarOffset, evs.byl.For(item));

            for (int ix = 0; ix < evs.bys.Length; ix++)
            {
                var valuey = CoerceValue(item, evs.bys[ix]);
                if (double.IsNaN(valuey))
                {
                    continue;
                }
                var colbase = valuey >= 0 ? sis.Max : sis.Min;
                var colend  = colbase + valuey;
                var y1      = ValueAxis.For(colend);
                var y2      = ValueAxis.For(colbase);
                var topy    = Math.Max(y1, y2);
                var bottomy = Math.Min(y1, y2);
                sis.UpdateLimits(y1);
                _trace.Verbose($"{Name}[{index},{ix}] {valuey} ({barx},{topy}) ({rightx},{bottomy}) sis ({sis.Min},{sis.Max})");
                var path = recycler.Next(null);
                if (path == null)
                {
                    return(null);
                }
                var shim = new GeometryWithOffsetShim <RectangleGeometry>()
                {
                    PathData = new RectangleGeometry()
                    {
                        Rect = new Rect(new Point(barx, topy), new Point(rightx, bottomy))
                    }
                };
                path.Item2.DataContext = shim;
                BindTo(ColumnStack[ix], "PathStyle", path.Item2, FrameworkElement.StyleProperty);
                // bind offset
                BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty);
                UpdateLimits(valuex, sis.Min, sis.Max);
                sis.Elements.Add(new Tuple <double, Path>(valuey, path.Item2));
            }
            return(sis);
        }
Esempio n. 11
0
        void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items)
        {
            // mimic the DSRP sequence
            var widx = LabelStyle?.Find(FrameworkElement.WidthProperty);
            var bl   = new BindingEvaluator(LabelPath);
            // keep a separate list; easier at the end
            var reproc = new List <ItemState>();

            for (int ix = 0; ix < items.Count; ix++)
            {
                // add requested item
                var label  = bl.For(items[ix]);
                var istate = makeit(startAt + ix, label, widx == null);
                AxisLabels.Insert(startAt + ix, istate);
                reproc.Add(istate);
            }
            // re-sequence remaining items
            for (int ix = startAt + reproc.Count; ix < AxisLabels.Count; ix++)
            {
                AxisLabels[ix].index = ix;
                AxisLabels[ix].value = ix;
            }
            // render new items
            // run the element pipeline on the added items
            var recycler = new Recycler <FrameworkElement, ItemState>(CreateElement);
            var labels   = new List <ICategoryLabelState>(AxisLabels);
            var sc       = new SelectorContext(this, icrc.SeriesArea, labels);

            foreach (var istate in reproc)
            {
                ElementPipeline(sc, istate, recycler);
            }
            // configure axis limits; just based on count-of-elements
            UpdateLimits(0);
            UpdateLimits(AxisLabels.Count);
            // finish up
            Layer.Add(recycler.Created);
            RebuildAxisGeometry();
            Dirty = false;
        }
Esempio n. 12
0
        object IDataSourceRenderer.Preamble(IChartRenderContext icrc)
        {
            if (Theme?.TextBlockTemplate == null)
            {
                // already reported an error so this should be no surprise
                return(null);
            }
            if (String.IsNullOrEmpty(LabelPath))
            {
                return(null);
            }
            var bl = new BindingEvaluator(LabelPath);

            if (bl == null)
            {
                return(null);
            }
            var recycler = new Recycler <FrameworkElement, ItemState>(AxisLabels.Where(tl => tl.element != null).Select(tl => tl.element), CreateElement);

            ResetLimits();
            var widx = LabelStyle?.Find(FrameworkElement.WidthProperty);

            return(new State(new List <ItemState>(), recycler, icrc, widx == null, bl));
        }
Esempio n. 13
0
 internal State(List <ItemState> state, Recycler <FrameworkElement, ItemState> rc, IChartRenderContext icrc, bool xau, BindingEvaluator bl) : base(state, rc)
 {
     this.icrc = icrc;
     usexau    = xau;
     this.bl   = bl;
 }
Esempio n. 14
0
        /// <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);
        }
Esempio n. 15
0
 internal State(List <SeriesItemState> sis, Recycler <Path, SeriesItemState> rc, Evaluators evs) : base(sis, rc)
 {
     this.evs = evs;
 }
Esempio n. 16
0
 /// <summary>
 /// The recycler's iterator to generate the elements.
 /// </summary>
 /// <summary>
 /// Ctor.
 /// </summary>
 /// <param name="state">Starting state; SHOULD be empty.</param>
 /// <param name="rc">The recycler.</param>
 internal RenderStateCore(List <SIS> state, Recycler <EL, SIS> rc)
 {
     itemstate = state;
     recycler  = rc;
 }
Esempio n. 17
0
        /// <summary>
        /// Grid coordinates:
        ///		x: "normalized" [0..1] and scaled to the area-width
        ///		y: "axis" scale
        /// </summary>
        /// <param name="icrc"></param>
        void IRequireRender.Render(IChartRenderContext icrc)
        {
            if (ValueAxis == null)
            {
                return;
            }
            if (double.IsNaN(ValueAxis.Maximum) || double.IsNaN(ValueAxis.Minimum))
            {
                return;
            }
            // grid lines
            var tc       = new TickCalculator(ValueAxis.Minimum, ValueAxis.Maximum);
            var recycler = new Recycler <Path, ItemState>(GridLines.Where(tl => tl.Element != null).Select(tl => tl.Element), (ist) => {
                return(CreateElement(ist));
            });
            var mrecycler = new Recycler <Path, ItemState>(MinorGridLines.Where(tl => tl.Element != null).Select(tl => tl.Element), (ist) => {
                return(CreateSubElement(ist));
            });
            var itemstate  = new List <ItemState>();
            var mitemstate = new List <ItemState>();
            //_trace.Verbose($"grid range:{tc.Range} tintv:{tc.TickInterval}");
            var tixarray = tc.GetTicks().ToArray();
            var sc       = new ValueAxisSelectorContext(ValueAxis, icrc.SeriesArea, tixarray, tc.TickInterval);

            for (int ix = 0; ix < tixarray.Length; ix++)
            {
                var tick = tixarray[ix];
                //_trace.Verbose($"grid vx:{tick}");
                var state = new ItemState()
                {
                    Tick = tick
                };
                var current = recycler.Next(state);
                if (!current.Item1)
                {
                    // restore binding
                    if (PathStyle != null)
                    {
                        BindTo(this, nameof(PathStyle), current.Item2, FrameworkElement.StyleProperty);
                    }
                }
                state.Element = current.Item2;
                ApplyBinding(this, nameof(Visibility), state.Element, UIElement.VisibilityProperty);
                if (PathFormatter != null)
                {
                    sc.SetTick(ix);
                    // call for Style, String override
                    var format = PathFormatter.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;
                        }
                    }
                }
                state.SetLocation(icrc.Area.Left, tick.Value);
                sc.Generated(tick);
                itemstate.Add(state);
                if (MinorGridLineCount != 0)
                {
                    // lay out minor divisions
                    var mintv = tc.TickInterval / (double)(MinorGridLineCount + 1);
                    var diry  = Math.Sign(tick.Index);
                    if (diry == 0)
                    {
                        // special case: zero
                        for (int mx = 1; mx <= MinorGridLineCount; mx++)
                        {
                            var mtick  = new SubtickState(tick.Index, mx, tick.Value + (double)mx * mintv);
                            var mstate = CreateSubtick(icrc, mrecycler, mtick);
                            if (mstate != null)
                            {
                                mitemstate.Add(mstate);
                            }
                            var mtick2  = new SubtickState(tick.Index, -mx, tick.Value + (double)(-mx) * mintv);
                            var mstate2 = CreateSubtick(icrc, mrecycler, mtick2);
                            if (mstate2 != null)
                            {
                                mitemstate.Add(mstate2);
                            }
                        }
                    }
                    else
                    {
                        for (int mx = 1; mx <= MinorGridLineCount; mx++)
                        {
                            var mtick  = new SubtickState(tick.Index, diry * mx, tick.Value + (double)(diry * mx) * mintv);
                            var mstate = CreateSubtick(icrc, mrecycler, mtick);
                            if (mstate != null)
                            {
                                mitemstate.Add(mstate);
                            }
                        }
                    }
                }
            }
            // VT and internal bookkeeping
            MinorGridLines = mitemstate;
            GridLines      = itemstate;
            Layer.Remove(mrecycler.Unused);
            Layer.Remove(recycler.Unused);
            Layer.Add(recycler.Created);
            Layer.Add(mrecycler.Created);
            Dirty = false;
        }
 internal State(List <ItemState <Path> > sis, Recycler <Path, ItemState <Path> > rc, params BindingEvaluator[] bes) : base(sis, rc, new Evaluators(bes[0], bes[2], bes[3]))
 {
     bl = bes[1];
 }
        /// <summary>
        /// Core element processing.
        /// The <see cref="RectangleGeometry"/> inside the <see cref="Path"/> is now location-invariant wrt x-axis.
        /// This means that during incremental updates, no re-calculation is required, only adjusting the <see cref="Canvas.LeftProperty"/>.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="valuex"></param>
        /// <param name="valuey"></param>
        /// <param name="item"></param>
        /// <param name="recycler"></param>
        /// <param name="byl"></param>
        /// <returns></returns>
        ItemState <Path> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator byl)
        {
            var y1      = ValueAxis.For(valuey);
            var y2      = ValueAxis.For(0);
            var topy    = Math.Max(y1, y2);
            var bottomy = Math.Min(y1, y2);
            var leftx   = CategoryAxis.For(valuex);
            var barx    = BarOffset;
            var rightx  = barx + BarWidth;

            _trace.Verbose($"{Name}[{index}] {valuey} ({barx},{topy}) ({rightx},{bottomy})");
            var path = recycler.Next(null);

            if (path == null)
            {
                return(null);
            }
            var shim = new GeometryWithOffsetShim <RectangleGeometry>()
            {
                PathData = new RectangleGeometry()
                {
                    Rect = new Rect(new Point(barx, topy), new Point(rightx, bottomy))
                }
            };

            path.Item2.DataContext = shim;
            // connect the shim to template root element's Visibility
            BindTo(shim, nameof(shim.Visibility), path.Item2, UIElement.VisibilityProperty);
            BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty);
            if (byl == null)
            {
                return(new SeriesItemState_Double(index, leftx, BarOffset, y1, path.Item2));
            }
            else
            {
                var cs = byl.For(item);
                return(new SeriesItemState_Custom(index, leftx, BarOffset, y1, cs, path.Item2));
            }
        }
        /// <summary>
        /// Core element processing.
        /// The <see cref="RectangleGeometry"/> inside the <see cref="Path"/> is now location-invariant wrt x-axis.
        /// This means that during incremental updates, no re-calculation is required, only adjusting the <see cref="Canvas.LeftProperty"/>.
        /// </summary>
        /// <param name="index">Data index.</param>
        /// <param name="valuec1">C1 (x-axis) index.</param>
        /// <param name="valuec2">C2 (y-axis) index.</param>
        /// <param name="value">Cell value.</param>
        /// <param name="item"></param>
        /// <param name="recycler"></param>
        /// <param name="byl"></param>
        /// <returns></returns>
        ItemState <Path> ElementPipeline(int index, int valuec1, int valuec2, double value, object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator byl)
        {
            var path = recycler.Next(null);

            if (path == null)
            {
                return(null);
            }
            var shim = new GeometryWith2OffsetShim <RectangleGeometry>()
            {
                // MUST use invariant geometry here so it can translate.
                PathData = new RectangleGeometry()
                {
                    Rect = new Rect(new Point(0, 0), new Point(1, 1))
                }
            };

            path.Item2.DataContext = shim;
            // connect the shim to template root element's Visibility
            BindTo(shim, nameof(shim.Visibility), path.Item2, UIElement.VisibilityProperty);
            BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty);
            BindTo(shim, nameof(shim.Offset2), path.Item2, Canvas.TopProperty);
            if (byl == null)
            {
                return(new SeriesItemState_Double(index, valuec1, 0, valuec2, value, path.Item2));
            }
            else
            {
                var cs = byl.For(item);
                return(new SeriesItemState_Custom(index, valuec1, 0, valuec2, value, cs, path.Item2));
            }
        }
Esempio n. 21
0
 internal State(List <ItemState <Path> > sis, Recycler <Path, ItemState <Path> > rc, Evaluators evs) : base(sis, rc)
 {
     this.evs = evs;
 }
Esempio n. 22
0
        ItemState <Path> ElementPipeline(
            int index, double valuex, double valueO, double valueH, double valueL, double valueC,
            object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator bvl
            )
        {
            // map through axes
            var y1      = ValueAxis.For(valueO);
            var y2      = ValueAxis.For(valueC);
            var y3      = ValueAxis.For(valueH);
            var y4      = ValueAxis.For(valueL);
            var leftx   = CategoryAxis.For(valuex);
            var offsetx = BarOffset;
            var rightx  = offsetx + BarWidth;
            // force them to be a min/max
            var topy    = Math.Max(y1, y2);
            var bottomy = Math.Min(y1, y2);
            var highy   = Math.Max(y3, y4);
            var lowy    = Math.Min(y3, y4);

            _trace.Verbose($"{Name}[{index}] {valueO}/{valueH}/{valueL}/{valueC} ({offsetx},{topy}) ({rightx},{bottomy})");
            // create geometry
            var path = recycler.Next(null);

            if (path == null)
            {
                return(null);
            }
            var pg = new PathGeometry();
            // body (open/close)
            var body = PathHelper.Rectangle(offsetx, topy, rightx, bottomy);

            pg.Figures.Add(body);
            // upper shadow (high)
            var centerx = offsetx + (rightx - offsetx) / 2;
            var upper   = PathHelper.Line(centerx, topy, centerx, highy);

            pg.Figures.Add(upper);
            // lower shadow (low)
            var lower = PathHelper.Line(centerx, bottomy, centerx, lowy);

            pg.Figures.Add(lower);
            var shim = new GeometryWithOffsetShim <PathGeometry>()
            {
                PathData = pg
            };

            path.Item2.DataContext = shim;
            // establish the style for "forward" or "reverse" polarity
            BindTo(this, valueO < valueC ? nameof(PathStyle) : nameof(ReversePathStyle), path.Item2, Path.StyleProperty);
            // bind offset
            BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty);
            var figs = new Tuple <double, PathFigure> [4];

            figs[0] = new Tuple <double, PathFigure>(y1, body);
            figs[1] = new Tuple <double, PathFigure>(y2, body);
            figs[2] = new Tuple <double, PathFigure>(y3, upper);
            figs[3] = new Tuple <double, PathFigure>(y4, lower);
            if (bvl == null)
            {
                return(new SeriesItemState(index, leftx, BarOffset, y1, path.Item2, figs));
            }
            else
            {
                var cs = bvl.For(item);
                return(new SeriesItemState_Custom(index, leftx, BarOffset, y1, cs, path.Item2, figs));
            }
        }
        /// <summary>
        /// Core element creation.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="valuex"></param>
        /// <param name="valuey"></param>
        /// <param name="item"></param>
        /// <param name="recycler"></param>
        /// <param name="evs"></param>
        /// <returns></returns>
        ItemState <Path> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Path, ItemState <Path> > recycler, Evaluators evs)
        {
            var mappedy = ValueAxis.For(valuey);
            var mappedx = CategoryAxis.For(valuex);
            var markerx = mappedx + MarkerOffset;

            _trace.Verbose($"[{index}] {valuey} ({markerx},{mappedy})");
            var mk = MarkerTemplate.LoadContent() as Geometry;
            // TODO allow MK to be other things like (Path or Image).
            // TODO allow a MarkerTemplateSelector and a value Selector/Formatter
            // no path yet
            var el = recycler.Next(null);

            if (el == null)
            {
                return(null);
            }
            var shim = new GeometryWithOffsetShim <Geometry>()
            {
                PathData = mk
            };

            el.Item2.DataContext = shim;
            BindTo(shim, nameof(shim.Offset), el.Item2, Canvas.LeftProperty);
            var cs = evs.LabelFor(item);

            if (cs == null)
            {
                return(new ItemState_Matrix <Path>(index, mappedx, MarkerOffset, mappedy, el.Item2));
            }
            else
            {
                return(new ItemStateCustom_Matrix <Path>(index, mappedx, MarkerOffset, mappedy, cs, el.Item2));
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Core element creation.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="valuex"></param>
        /// <param name="valuey"></param>
        /// <param name="item"></param>
        /// <param name="recycler"></param>
        /// <param name="evs"></param>
        /// <returns></returns>
        ItemState <Image> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Image, ItemState <Image> > recycler, Evaluators evs)
        {
            var mappedy = ValueAxis.For(valuey);
            var mappedx = CategoryAxis.For(valuex);
            var markerx = mappedx + MarkerOffset;

            _trace.Verbose($"[{index}] {valuey} ({markerx},{mappedy})");
            // TODO allow a MarkerTemplateSelector and a value Selector/Formatter
            // no path yet
            var el = recycler.Next(null);

            if (el == null)
            {
                return(null);
            }
            var cs = evs.LabelFor(item);

            if (cs == null)
            {
                return(new ItemState_Matrix <Image>(index, mappedx, MarkerOffset, mappedy, el.Item2));
            }
            else
            {
                return(new ItemStateCustom_Matrix <Image>(index, mappedx, MarkerOffset, mappedy, cs, el.Item2));
            }
        }