External/OxyPlot/OxyPlot/PlotModel/PlotModel.Rendering.cs
author moel.mich
Sun, 14 Jul 2013 14:04:44 +0000
changeset 411 9e208c26722f
parent 399 54048d90a678
permissions -rw-r--r--
Improved the code used to draw a line between the different OxyPlot subplots.
moel@391
     1
// --------------------------------------------------------------------------------------------------------------------
moel@391
     2
// <copyright file="PlotModel.Rendering.cs" company="OxyPlot">
moel@391
     3
//   The MIT License (MIT)
moel@391
     4
//
moel@391
     5
//   Copyright (c) 2012 Oystein Bjorke
moel@391
     6
//
moel@391
     7
//   Permission is hereby granted, free of charge, to any person obtaining a
moel@391
     8
//   copy of this software and associated documentation files (the
moel@391
     9
//   "Software"), to deal in the Software without restriction, including
moel@391
    10
//   without limitation the rights to use, copy, modify, merge, publish,
moel@391
    11
//   distribute, sublicense, and/or sell copies of the Software, and to
moel@391
    12
//   permit persons to whom the Software is furnished to do so, subject to
moel@391
    13
//   the following conditions:
moel@391
    14
//
moel@391
    15
//   The above copyright notice and this permission notice shall be included
moel@391
    16
//   in all copies or substantial portions of the Software.
moel@391
    17
//
moel@391
    18
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
moel@391
    19
//   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
moel@391
    20
//   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
moel@391
    21
//   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
moel@391
    22
//   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
moel@391
    23
//   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
moel@391
    24
//   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
moel@391
    25
// </copyright>
moel@391
    26
// <summary>
moel@391
    27
//   Partial PlotModel class - this file contains rendering methods.
moel@391
    28
// </summary>
moel@391
    29
// --------------------------------------------------------------------------------------------------------------------
moel@391
    30
namespace OxyPlot
moel@391
    31
{
moel@391
    32
    using System;
moel@391
    33
    using System.Collections.Generic;
moel@391
    34
    using System.Linq;
moel@391
    35
moel@391
    36
    using OxyPlot.Annotations;
moel@391
    37
    using OxyPlot.Axes;
moel@391
    38
    using OxyPlot.Series;
moel@391
    39
moel@391
    40
    public partial class PlotModel
moel@391
    41
    {
moel@391
    42
        /// <summary>
moel@391
    43
        /// Renders the plot with the specified rendering context.
moel@391
    44
        /// </summary>
moel@391
    45
        /// <param name="rc">The rendering context.</param>
moel@391
    46
        /// <param name="width">The width.</param>
moel@391
    47
        /// <param name="height">The height.</param>
moel@391
    48
        public void Render(IRenderContext rc, double width, double height)
moel@391
    49
        {
moel@391
    50
            lock (this.syncRoot)
moel@391
    51
            {
moel@391
    52
                if (width <= 0 || height <= 0)
moel@391
    53
                {
moel@391
    54
                    return;
moel@391
    55
                }
moel@391
    56
                
moel@391
    57
                this.Width = width;
moel@391
    58
                this.Height = height;
moel@391
    59
moel@391
    60
                this.ActualPlotMargins = this.PlotMargins;
moel@391
    61
                this.EnsureLegendProperties();
moel@391
    62
moel@391
    63
                while (true)
moel@391
    64
                {
moel@391
    65
                    this.UpdatePlotArea(rc);
moel@391
    66
                    this.UpdateAxisTransforms();
moel@391
    67
                    this.UpdateIntervals();
moel@391
    68
                    if (!this.AutoAdjustPlotMargins)
moel@391
    69
                    {
moel@391
    70
                        break;
moel@391
    71
                    }
moel@391
    72
moel@391
    73
                    if (!this.AdjustPlotMargins(rc))
moel@391
    74
                    {
moel@391
    75
                        break;
moel@391
    76
                    }
moel@391
    77
                }
moel@391
    78
moel@391
    79
                if (this.PlotType == PlotType.Cartesian)
moel@391
    80
                {
moel@391
    81
                    this.EnforceCartesianTransforms();
moel@391
    82
                    this.UpdateIntervals();
moel@391
    83
                }
moel@391
    84
moel@391
    85
                this.RenderBackgrounds(rc);
moel@391
    86
                this.RenderAnnotations(rc, AnnotationLayer.BelowAxes);
moel@391
    87
                this.RenderAxes(rc, AxisLayer.BelowSeries);
moel@391
    88
                this.RenderAnnotations(rc, AnnotationLayer.BelowSeries);
moel@391
    89
                this.RenderSeries(rc);
moel@391
    90
                this.RenderAnnotations(rc, AnnotationLayer.AboveSeries);
moel@391
    91
                this.RenderTitle(rc);
moel@391
    92
                this.RenderBox(rc);
moel@391
    93
                this.RenderAxes(rc, AxisLayer.AboveSeries);
moel@391
    94
moel@391
    95
                if (this.IsLegendVisible)
moel@391
    96
                {
moel@391
    97
                    this.RenderLegends(rc, this.LegendArea);
moel@391
    98
                }
moel@391
    99
            }
moel@391
   100
        }
moel@391
   101
moel@391
   102
        /// <summary>
moel@391
   103
        /// Calculates the maximum size of the specified axes.
moel@391
   104
        /// </summary>
moel@391
   105
        /// <param name="rc">
moel@391
   106
        /// The render context.
moel@391
   107
        /// </param>
moel@391
   108
        /// <param name="axesOfPositionTier">
moel@391
   109
        /// The axes of position tier.
moel@391
   110
        /// </param>
moel@391
   111
        /// <returns>
moel@391
   112
        /// The maximum size.
moel@391
   113
        /// </returns>
moel@391
   114
        private static double MaxSizeOfPositionTier(IRenderContext rc, IEnumerable<Axis> axesOfPositionTier)
moel@391
   115
        {
moel@391
   116
            double maxSizeOfPositionTier = 0;
moel@391
   117
            foreach (var axis in axesOfPositionTier)
moel@391
   118
            {
moel@391
   119
                OxySize size = axis.Measure(rc);
moel@391
   120
                if (axis.IsHorizontal())
moel@391
   121
                {
moel@391
   122
                    if (size.Height > maxSizeOfPositionTier)
moel@391
   123
                    {
moel@391
   124
                        maxSizeOfPositionTier = size.Height;
moel@391
   125
                    }
moel@391
   126
                }
moel@391
   127
                else
moel@391
   128
                {
moel@391
   129
                    if (size.Width > maxSizeOfPositionTier)
moel@391
   130
                    {
moel@391
   131
                        maxSizeOfPositionTier = size.Width;
moel@391
   132
                    }
moel@391
   133
                }
moel@391
   134
            }
moel@391
   135
moel@391
   136
            return maxSizeOfPositionTier;
moel@391
   137
        }
moel@391
   138
moel@391
   139
        /// <summary>
moel@391
   140
        /// Adjust the plot margins.
moel@391
   141
        /// </summary>
moel@391
   142
        /// <param name="rc">
moel@391
   143
        /// The render context.
moel@391
   144
        /// </param>
moel@391
   145
        /// <returns>
moel@391
   146
        /// The adjust plot margins.
moel@391
   147
        /// </returns>
moel@391
   148
        private bool AdjustPlotMargins(IRenderContext rc)
moel@391
   149
        {
moel@391
   150
            bool isAdjusted = false;
moel@391
   151
            var newPlotMargins = new Dictionary<AxisPosition, double>
moel@391
   152
                {
moel@391
   153
                    { AxisPosition.Left, this.ActualPlotMargins.Left },
moel@391
   154
                    { AxisPosition.Top, this.ActualPlotMargins.Top },
moel@391
   155
                    { AxisPosition.Right, this.ActualPlotMargins.Right },
moel@391
   156
                    { AxisPosition.Bottom, this.ActualPlotMargins.Bottom }
moel@391
   157
                };
moel@391
   158
moel@391
   159
            for (var position = AxisPosition.Left; position <= AxisPosition.Bottom; position++)
moel@391
   160
            {
moel@391
   161
                double maxValueOfPositionTier = 0;
moel@391
   162
                var axesOfPosition = this.Axes.Where(a => a.Position == position).ToList();
moel@391
   163
                foreach (var positionTier in axesOfPosition.Select(a => a.PositionTier).Distinct().OrderBy(l => l))
moel@391
   164
                {
moel@391
   165
                    var axesOfPositionTier = axesOfPosition.Where(a => a.PositionTier == positionTier).ToList();
moel@391
   166
                    double maxSizeOfPositionTier = MaxSizeOfPositionTier(rc, axesOfPositionTier);
moel@391
   167
                    double minValueOfPositionTier = maxValueOfPositionTier;
moel@391
   168
moel@391
   169
                    if (Math.Abs(maxValueOfPositionTier) > 1e-5)
moel@391
   170
                    {
moel@391
   171
                        maxValueOfPositionTier += this.AxisTierDistance;
moel@391
   172
                    }
moel@391
   173
moel@391
   174
                    maxValueOfPositionTier += maxSizeOfPositionTier;
moel@391
   175
moel@391
   176
                    foreach (Axis axis in axesOfPositionTier)
moel@391
   177
                    {
moel@391
   178
                        axis.PositionTierSize = maxSizeOfPositionTier;
moel@391
   179
                        axis.PositionTierMinShift = minValueOfPositionTier;
moel@391
   180
                        axis.PositionTierMaxShift = maxValueOfPositionTier;
moel@391
   181
                    }
moel@391
   182
                }
moel@391
   183
moel@391
   184
                if (maxValueOfPositionTier > newPlotMargins[position])
moel@391
   185
                {
moel@391
   186
                    newPlotMargins[position] = maxValueOfPositionTier;
moel@391
   187
                    isAdjusted = true;
moel@391
   188
                }
moel@391
   189
            }
moel@391
   190
moel@391
   191
            if (isAdjusted)
moel@391
   192
            {
moel@391
   193
                this.ActualPlotMargins = new OxyThickness(
moel@391
   194
                    newPlotMargins[AxisPosition.Left],
moel@391
   195
                    newPlotMargins[AxisPosition.Top],
moel@391
   196
                    newPlotMargins[AxisPosition.Right],
moel@391
   197
                    newPlotMargins[AxisPosition.Bottom]);
moel@391
   198
            }
moel@391
   199
moel@391
   200
            return isAdjusted;
moel@391
   201
        }
moel@391
   202
moel@391
   203
        /// <summary>
moel@391
   204
        /// Measures the size of the title and subtitle.
moel@391
   205
        /// </summary>
moel@391
   206
        /// <param name="rc">
moel@391
   207
        /// The rendering context.
moel@391
   208
        /// </param>
moel@391
   209
        /// <returns>
moel@391
   210
        /// Size of the titles.
moel@391
   211
        /// </returns>
moel@391
   212
        private OxySize MeasureTitles(IRenderContext rc)
moel@391
   213
        {
moel@391
   214
            OxySize size1 = rc.MeasureText(this.Title, this.ActualTitleFont, this.TitleFontSize, this.TitleFontWeight);
moel@391
   215
            OxySize size2 = rc.MeasureText(
moel@391
   216
                this.Subtitle, this.SubtitleFont ?? this.ActualSubtitleFont, this.SubtitleFontSize, this.SubtitleFontWeight);
moel@391
   217
            double height = size1.Height + size2.Height;
moel@391
   218
            double width = Math.Max(size1.Width, size2.Width);
moel@391
   219
            return new OxySize(width, height);
moel@391
   220
        }
moel@391
   221
moel@391
   222
        /// <summary>
moel@391
   223
        /// Renders the annotations.
moel@391
   224
        /// </summary>
moel@391
   225
        /// <param name="rc">
moel@391
   226
        /// The render context.
moel@391
   227
        /// </param>
moel@391
   228
        /// <param name="layer">
moel@391
   229
        /// The layer.
moel@391
   230
        /// </param>
moel@391
   231
        private void RenderAnnotations(IRenderContext rc, AnnotationLayer layer)
moel@391
   232
        {
moel@391
   233
            foreach (var a in this.Annotations.Where(a => a.Layer == layer))
moel@391
   234
            {
moel@391
   235
                a.Render(rc, this);
moel@391
   236
            }
moel@391
   237
        }
moel@391
   238
moel@391
   239
        /// <summary>
moel@391
   240
        /// Renders the axes.
moel@391
   241
        /// </summary>
moel@391
   242
        /// <param name="rc">
moel@391
   243
        /// The render context.
moel@391
   244
        /// </param>
moel@391
   245
        /// <param name="layer">
moel@391
   246
        /// The layer.
moel@391
   247
        /// </param>
moel@391
   248
        private void RenderAxes(IRenderContext rc, AxisLayer layer)
moel@391
   249
        {
moel@391
   250
            for (int i = 0; i < 2; i++)
moel@391
   251
            {
moel@391
   252
                foreach (var a in this.Axes)
moel@391
   253
                {
moel@391
   254
                    if (a.IsAxisVisible && a.Layer == layer)
moel@391
   255
                    {
moel@391
   256
                        a.Render(rc, this, layer, i);
moel@391
   257
                    }
moel@391
   258
                }
moel@391
   259
            }
moel@391
   260
        }
moel@391
   261
moel@391
   262
        /// <summary>
moel@391
   263
        /// Renders the series backgrounds.
moel@391
   264
        /// </summary>
moel@391
   265
        /// <param name="rc">
moel@391
   266
        /// The render context.
moel@391
   267
        /// </param>
moel@391
   268
        private void RenderBackgrounds(IRenderContext rc)
moel@391
   269
        {
moel@391
   270
            // Render the main background of the plot area (only if there are axes)
moel@391
   271
            // The border is rendered by DrawRectangleAsPolygon to ensure that it is pixel aligned with the tick marks.
moel@391
   272
            if (this.Axes.Count > 0 && this.PlotAreaBackground != null)
moel@391
   273
            {
moel@391
   274
                rc.DrawRectangleAsPolygon(this.PlotArea, this.PlotAreaBackground, null, 0);
moel@391
   275
            }
moel@391
   276
moel@391
   277
            foreach (var s in this.VisibleSeries)
moel@391
   278
            {
moel@391
   279
                var s2 = s as XYAxisSeries;
moel@391
   280
                if (s2 == null || s2.Background == null)
moel@391
   281
                {
moel@391
   282
                    continue;
moel@391
   283
                }
moel@391
   284
moel@391
   285
                rc.DrawRectangle(s2.GetScreenRectangle(), s2.Background, null, 0);
moel@391
   286
            }
moel@391
   287
        }
moel@391
   288
moel@391
   289
        /// <summary>
moel@391
   290
        /// Renders the border around the plot area.
moel@391
   291
        /// </summary>
moel@391
   292
        /// <remarks>
moel@391
   293
        /// The border will only by rendered if there are axes in the plot.
moel@391
   294
        /// </remarks>
moel@391
   295
        /// <param name="rc">
moel@391
   296
        /// The render context.
moel@391
   297
        /// </param>
moel@391
   298
        private void RenderBox(IRenderContext rc)
moel@391
   299
        {
moel@391
   300
            // The border is rendered by DrawBox to ensure that it is pixel aligned with the tick marks (cannot use DrawRectangle here).
moel@391
   301
            if (this.Axes.Count > 0)
moel@391
   302
            {
moel@391
   303
                rc.DrawRectangleAsPolygon(this.PlotArea, null, this.PlotAreaBorderColor, this.PlotAreaBorderThickness);
moel@399
   304
moel@411
   305
                foreach (var axis in this.Axes) 
moel@411
   306
                {
moel@411
   307
                    if (!axis.IsAxisVisible)
moel@411
   308
                        continue;
moel@399
   309
moel@411
   310
                    if (axis.IsHorizontal()) 
moel@411
   311
                    {
moel@411
   312
                        var start = this.PlotArea.Left + 
moel@411
   313
                            this.PlotArea.Width * axis.StartPosition;
moel@411
   314
                        if (axis.StartPosition < 1 && axis.StartPosition > 0)
moel@411
   315
                            rc.DrawLine(new[] {
moel@411
   316
                                new ScreenPoint(start, this.PlotArea.Top),
moel@411
   317
                                new ScreenPoint(start, this.PlotArea.Bottom) },
moel@411
   318
                                    this.PlotAreaBorderColor, this.PlotAreaBorderThickness,
moel@411
   319
                                null, OxyPenLineJoin.Miter, true);
moel@399
   320
moel@411
   321
                        var end = this.PlotArea.Left +
moel@411
   322
                            this.PlotArea.Width * axis.EndPosition;
moel@411
   323
                        if (axis.EndPosition < 1 && axis.EndPosition > 0)
moel@411
   324
                            rc.DrawLine(new[] {
moel@411
   325
                                new ScreenPoint(end, this.PlotArea.Top),
moel@411
   326
                                new ScreenPoint(end, this.PlotArea.Bottom) },
moel@411
   327
                                    this.PlotAreaBorderColor, this.PlotAreaBorderThickness,
moel@411
   328
                                null, OxyPenLineJoin.Miter, true);
moel@411
   329
                    } 
moel@411
   330
                    else 
moel@411
   331
                    {
moel@411
   332
                        var start = this.PlotArea.Bottom - 
moel@411
   333
                            this.PlotArea.Height * axis.StartPosition;
moel@411
   334
                        if (axis.StartPosition < 1 && axis.StartPosition > 0)
moel@411
   335
                            rc.DrawLine(new[] { 
moel@411
   336
                                new ScreenPoint(this.PlotArea.Left, start),
moel@411
   337
                                new ScreenPoint(this.PlotArea.Right, start) },
moel@411
   338
                                    this.PlotAreaBorderColor, this.PlotAreaBorderThickness,
moel@411
   339
                                null, OxyPenLineJoin.Miter, true);
moel@411
   340
moel@411
   341
                        var end = this.PlotArea.Bottom -
moel@411
   342
                            this.PlotArea.Height * axis.EndPosition;
moel@411
   343
                        if (axis.EndPosition < 1 && axis.EndPosition > 0)
moel@411
   344
                            rc.DrawLine(new[] { 
moel@411
   345
                                new ScreenPoint(this.PlotArea.Left, end),
moel@411
   346
                                new ScreenPoint(this.PlotArea.Right, end) },
moel@411
   347
                                    this.PlotAreaBorderColor, this.PlotAreaBorderThickness,
moel@411
   348
                                null, OxyPenLineJoin.Miter, true);
moel@411
   349
                    }
moel@399
   350
                }
moel@411
   351
moel@391
   352
            }
moel@391
   353
        }
moel@391
   354
moel@391
   355
        /// <summary>
moel@391
   356
        /// Renders the series.
moel@391
   357
        /// </summary>
moel@391
   358
        /// <param name="rc">
moel@391
   359
        /// The render context.
moel@391
   360
        /// </param>
moel@391
   361
        private void RenderSeries(IRenderContext rc)
moel@391
   362
        {
moel@391
   363
            // Update undefined colors
moel@391
   364
            this.ResetDefaultColor();
moel@391
   365
            foreach (var s in this.VisibleSeries)
moel@391
   366
            {
moel@391
   367
                s.SetDefaultValues(this);
moel@391
   368
            }
moel@391
   369
moel@391
   370
            foreach (var s in this.VisibleSeries)
moel@391
   371
            {
moel@391
   372
                s.Render(rc, this);
moel@391
   373
            }
moel@391
   374
        }
moel@391
   375
moel@391
   376
        /// <summary>
moel@391
   377
        /// Renders the title and subtitle.
moel@391
   378
        /// </summary>
moel@391
   379
        /// <param name="rc">
moel@391
   380
        /// The render context.
moel@391
   381
        /// </param>
moel@391
   382
        private void RenderTitle(IRenderContext rc)
moel@391
   383
        {
moel@391
   384
            OxySize size1 = rc.MeasureText(this.Title, this.ActualTitleFont, this.TitleFontSize, this.TitleFontWeight);
moel@391
   385
            rc.MeasureText(
moel@391
   386
                this.Subtitle, this.SubtitleFont ?? this.ActualSubtitleFont, this.SubtitleFontSize, this.SubtitleFontWeight);
moel@391
   387
moel@391
   388
            // double height = size1.Height + size2.Height;
moel@391
   389
            // double dy = (TitleArea.Top+TitleArea.Bottom-height)*0.5;
moel@391
   390
            double dy = this.TitleArea.Top;
moel@391
   391
            double dx = (this.TitleArea.Left + this.TitleArea.Right) * 0.5;
moel@391
   392
moel@391
   393
            if (!string.IsNullOrEmpty(this.Title))
moel@391
   394
            {
moel@391
   395
                rc.DrawMathText(
moel@391
   396
                    new ScreenPoint(dx, dy),
moel@391
   397
                    this.Title,
moel@391
   398
                    this.TitleColor ?? this.TextColor,
moel@391
   399
                    this.ActualTitleFont,
moel@391
   400
                    this.TitleFontSize,
moel@391
   401
                    this.TitleFontWeight,
moel@391
   402
                    0,
moel@391
   403
                    HorizontalAlignment.Center,
moel@391
   404
                    VerticalAlignment.Top);
moel@391
   405
                dy += size1.Height;
moel@391
   406
            }
moel@391
   407
moel@391
   408
            if (!string.IsNullOrEmpty(this.Subtitle))
moel@391
   409
            {
moel@391
   410
                rc.DrawMathText(
moel@391
   411
                    new ScreenPoint(dx, dy),
moel@391
   412
                    this.Subtitle,
moel@391
   413
                    this.SubtitleColor ?? this.TextColor,
moel@391
   414
                    this.ActualSubtitleFont,
moel@391
   415
                    this.SubtitleFontSize,
moel@391
   416
                    this.SubtitleFontWeight,
moel@391
   417
                    0,
moel@391
   418
                    HorizontalAlignment.Center,
moel@391
   419
                    VerticalAlignment.Top);
moel@391
   420
            }
moel@391
   421
        }
moel@391
   422
moel@391
   423
        /// <summary>
moel@391
   424
        /// Calculates the plot area (subtract padding, title size and outside legends)
moel@391
   425
        /// </summary>
moel@391
   426
        /// <param name="rc">
moel@391
   427
        /// The rendering context.
moel@391
   428
        /// </param>
moel@391
   429
        private void UpdatePlotArea(IRenderContext rc)
moel@391
   430
        {
moel@391
   431
            var plotArea = new OxyRect(
moel@391
   432
                this.Padding.Left,
moel@391
   433
                this.Padding.Top,
moel@391
   434
                this.Width - this.Padding.Left - this.Padding.Right,
moel@391
   435
                this.Height - this.Padding.Top - this.Padding.Bottom);
moel@391
   436
moel@391
   437
            var titleSize = this.MeasureTitles(rc);
moel@391
   438
moel@391
   439
            if (titleSize.Height > 0)
moel@391
   440
            {
moel@391
   441
                double titleHeight = titleSize.Height + this.TitlePadding;
moel@391
   442
                plotArea.Height -= titleHeight;
moel@391
   443
                plotArea.Top += titleHeight;
moel@391
   444
            }
moel@391
   445
moel@391
   446
            plotArea.Top += this.ActualPlotMargins.Top;
moel@391
   447
            plotArea.Height -= this.ActualPlotMargins.Top;
moel@391
   448
moel@391
   449
            plotArea.Height -= this.ActualPlotMargins.Bottom;
moel@391
   450
moel@391
   451
            plotArea.Left += this.ActualPlotMargins.Left;
moel@391
   452
            plotArea.Width -= this.ActualPlotMargins.Left;
moel@391
   453
moel@391
   454
            plotArea.Width -= this.ActualPlotMargins.Right;
moel@391
   455
moel@391
   456
            // Find the available size for the legend box
moel@391
   457
            double availableLegendWidth = plotArea.Width;
moel@391
   458
            double availableLegendHeight = plotArea.Height;
moel@391
   459
            if (this.LegendPlacement == LegendPlacement.Inside)
moel@391
   460
            {
moel@391
   461
                availableLegendWidth -= this.LegendMargin * 2;
moel@391
   462
                availableLegendHeight -= this.LegendMargin * 2;
moel@391
   463
            }
moel@391
   464
moel@391
   465
            if (availableLegendWidth < 0)
moel@391
   466
            {
moel@391
   467
                availableLegendWidth = 0;
moel@391
   468
            }
moel@391
   469
moel@391
   470
            if (availableLegendHeight < 0)
moel@391
   471
            {
moel@391
   472
                availableLegendHeight = 0;
moel@391
   473
            }
moel@391
   474
moel@391
   475
            // Calculate the size of the legend box
moel@391
   476
            var legendSize = this.MeasureLegends(rc, new OxySize(availableLegendWidth, availableLegendHeight));
moel@391
   477
moel@391
   478
            // Adjust the plot area after the size of the legend box has been calculated
moel@391
   479
            if (this.IsLegendVisible && this.LegendPlacement == LegendPlacement.Outside)
moel@391
   480
            {
moel@391
   481
                switch (this.LegendPosition)
moel@391
   482
                {
moel@391
   483
                    case LegendPosition.LeftTop:
moel@391
   484
                    case LegendPosition.LeftMiddle:
moel@391
   485
                    case LegendPosition.LeftBottom:
moel@391
   486
                        plotArea.Left += legendSize.Width + this.LegendMargin;
moel@391
   487
                        plotArea.Width -= legendSize.Width + this.LegendMargin;
moel@391
   488
                        break;
moel@391
   489
                    case LegendPosition.RightTop:
moel@391
   490
                    case LegendPosition.RightMiddle:
moel@391
   491
                    case LegendPosition.RightBottom:
moel@391
   492
                        plotArea.Width -= legendSize.Width + this.LegendMargin;
moel@391
   493
                        break;
moel@391
   494
                    case LegendPosition.TopLeft:
moel@391
   495
                    case LegendPosition.TopCenter:
moel@391
   496
                    case LegendPosition.TopRight:
moel@391
   497
                        plotArea.Top += legendSize.Height + this.LegendMargin;
moel@391
   498
                        plotArea.Height -= legendSize.Height + this.LegendMargin;
moel@391
   499
                        break;
moel@391
   500
                    case LegendPosition.BottomLeft:
moel@391
   501
                    case LegendPosition.BottomCenter:
moel@391
   502
                    case LegendPosition.BottomRight:
moel@391
   503
                        plotArea.Height -= legendSize.Height + this.LegendMargin;
moel@391
   504
                        break;
moel@391
   505
                }
moel@391
   506
            }
moel@391
   507
moel@391
   508
            // Ensure the plot area is valid
moel@391
   509
            if (plotArea.Height < 0)
moel@391
   510
            {
moel@391
   511
                plotArea.Bottom = plotArea.Top + 1;
moel@391
   512
            }
moel@391
   513
moel@391
   514
            if (plotArea.Width < 0)
moel@391
   515
            {
moel@391
   516
                plotArea.Right = plotArea.Left + 1;
moel@391
   517
            }
moel@391
   518
moel@391
   519
            this.PlotArea = plotArea;
moel@391
   520
            this.PlotAndAxisArea = new OxyRect(
moel@391
   521
                plotArea.Left - this.ActualPlotMargins.Left,
moel@391
   522
                plotArea.Top - this.ActualPlotMargins.Top,
moel@391
   523
                plotArea.Width + this.ActualPlotMargins.Left + this.ActualPlotMargins.Right,
moel@391
   524
                plotArea.Height + this.ActualPlotMargins.Top + this.ActualPlotMargins.Bottom);
moel@391
   525
            this.TitleArea = new OxyRect(this.PlotArea.Left, this.Padding.Top, this.PlotArea.Width, titleSize.Height + (this.TitlePadding * 2));
moel@391
   526
            this.LegendArea = this.GetLegendRectangle(legendSize);
moel@391
   527
        }
moel@391
   528
    }
moel@391
   529
}