/// <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));
            }
        }
        Legend Legend()
        {
            var mk = MarkerTemplate?.LoadContent();

            if (mk is Geometry gx)
            {
                // need something because it's all in NDC
                gx.Transform = new ScaleTransform()
                {
                    ScaleX = 24, ScaleY = 24
                };
                return(new LegendWithGeometry()
                {
                    Data = gx, Title = Title, Fill = PathStyle.Find <Brush>(Path.FillProperty), Stroke = PathStyle.Find <Brush>(Path.StrokeProperty)
                });
            }
            else
            {
                return(new Legend()
                {
                    Title = Title, Fill = PathStyle.Find <Brush>(Path.FillProperty), Stroke = PathStyle.Find <Brush>(Path.StrokeProperty)
                });
            }
        }
Esempio n. 3
0
        /// <summary>This method is invoked when application is in idle state</summary>
        void IdleDraw(object sender, EventArgs e)
        {
            bool finished = true;

            SyncMarkerViewModels();
            // Remove extra batches. Such removals take a lot of time, so we do it at idle handlers
            if (batches.Count > Math.Ceiling(models.Count / (double)MarkersBatchSize))
            {
                var b = batches[batches.Count - 1];
                Children.Remove(b.Panel);
                Children.Remove(b.Image);
                batches.RemoveAt(batches.Count - 1);
                finished = false;
            }
            // Find first batch that is ready for Image updating
            var batch = batches.FirstOrDefault(b => b.PanelVersion == plotVersion &&
                                               b.Panel.Visibility == System.Windows.Visibility.Visible &&
                                               b.IsLayoutUpdated &&
                                               b.ImageVersion != plotVersion);

            if (batch != null)
            {
                batch.PlotRect = ActualPlotRect;
                var panelSize  = new Size(Math.Max(1, batch.Panel.RenderSize.Width), Math.Max(1, batch.Panel.RenderSize.Height));
                var renderSize = new Size(
                    Math.Min(MaxSnapshotSize.Width, panelSize.Width),
                    Math.Min(MaxSnapshotSize.Height, panelSize.Height));
                if (batch.Content == null || batch.Content.PixelWidth != (int)Math.Ceiling(renderSize.Width) || batch.Content.PixelHeight != (int)Math.Ceiling(renderSize.Height))
                {
                    batch.Content = new RenderTargetBitmap((int)renderSize.Width, (int)renderSize.Height, 96, 96, PixelFormats.Pbgra32);
                }
                else
                {
                    batch.Content.Clear();
                }

                ScaleTransform transform = new ScaleTransform
                {
                    ScaleX = renderSize.Width < panelSize.Width ? renderSize.Width / panelSize.Width : 1.0,
                    ScaleY = renderSize.Height < panelSize.Height ? renderSize.Height / panelSize.Height : 1.0
                };
                var panel = batch.Panel;
                panel.RenderTransform = transform;
                batch.Content         = new RenderTargetBitmap((int)renderSize.Width, (int)renderSize.Height, 96, 96, PixelFormats.Pbgra32);
                batch.Content.Render(panel);
                batch.ImageVersion = plotVersion;
                finished           = false;
            }
            // Find first batch that should be rendered
            batch = batches.FirstOrDefault(b => b.PanelVersion != plotVersion);
            if (batch != null)
            {
                int idx = batches.IndexOf(batch);
                if (!batch.Panel.IsMaster && idx * MarkersBatchSize < models.Count)
                {
                    if (MarkerTemplate == null)
                    {
                        batch.Panel.Children.Clear();
                    }
                    else
                    {
                        int batchSize = Math.Min(MarkersBatchSize, models.Count - idx * MarkersBatchSize);
                        while (batch.Panel.Children.Count > batchSize)
                        {
                            batch.Panel.Children.RemoveAt(batch.Panel.Children.Count - 1);
                        }
                        for (int i = 0; i < batch.Panel.Children.Count; i++)
                        {
                            var mvm = models[i + idx * MarkersBatchSize];
                            var fe  = batch.Panel.Children[i] as FrameworkElement;
                            if (fe.DataContext != mvm)
                            {
                                fe.DataContext = mvm;
                            }
                            else
                            {
                                mvm.Notify(batch.ChangedProperties);
                            }
                        }
                        for (int i = batch.Panel.Children.Count; i < batchSize; i++)
                        {
                            var fe = MarkerTemplate.LoadContent() as FrameworkElement;
                            fe.DataContext = models[i + idx * MarkersBatchSize];
                            if (TooltipTemplate != null)
                            {
                                var tc = new ContentControl
                                {
                                    Content         = fe.DataContext,
                                    ContentTemplate = TooltipTemplate
                                };
                                ToolTipService.SetToolTip(fe, tc);
                            }
                            batch.Panel.Children.Add(fe);
                        }
                        markersDrawn += batchSize;
                    }
                    batch.IsLayoutUpdated       = false;
                    batch.Image.Visibility      = System.Windows.Visibility.Collapsed;
                    batch.Image.RenderTransform = null;
                    batch.Panel.Visibility      = System.Windows.Visibility.Visible;
                    batch.Panel.InvalidateMeasure();
                    batch.PanelVersion = plotVersion;
                    batch.ClearChangedProperties();
                }
                finished = false;
            }
            if (finished)
            {
                idleTask.Stop();
                isDrawing = false;
                if (currentTaskId != -1)
                {
                    renderCompletion.OnNext(new MarkerGraphRenderCompletion(currentTaskId, markersDrawn));
                    currentTaskId = -1;
                }
            }
        }