Commits

Anonymous committed ef87335

legend placement outside grid inside plot with grid shrinkage now working. Fixed bug in error catching on IE. NOTE: CHANGES IN placement option for legend. Now have inside == insideGrid (preferred), outsideGrid and outside. CHANGED error font config options. Also added css support to error display.

  • Participants
  • Parent commits 08e02de

Comments (0)

Files changed (15)

File examples/catchError.html

 
    plot1 = $.jqplot('chart1',[[]],{});
    
-   // Second plot will use these customizations to error display.
+   // Second plot will use these customizations to the plot target for error display.
    $.jqplot.config.errorMessage = 'A Plot Error has Occurred';
    $.jqplot.config.errorBackground = '#fbeddf';
    $.jqplot.config.errorBorder = '2px solid #aaaaaa';
-   $.jqplot.config.errorFont = '16pt Courier New';
-   
-   plot2 = $.jqplot('chart2',[],{
-       axes: {
-           xaxis: {
-               renderer: $.jqplot.BarRenderer.js
-           }
-       }
-   });
-   
-   // The third plot will not display any errors, error will be rethrown as normal.
-   $.jqplot.config.catchErrors = false;
+   $.jqplot.config.errorFontFamily = 'Courier New';
+   $.jqplot.config.errorFontSize = '16pt';
    
    plot2 = $.jqplot('chart2',[],{
        axes: {

File examples/dataLabels.html

             renderer:$.jqplot.PieRenderer,
             rendererOptions: {
                 showDataLabels: true,
-                dataLabelCenterOn: false,
-                dataLabelPositionFactor: 1.1,
+                // dataLabelCenterOn: false,   // This is an expreimental feature.
+                dataLabelPositionFactor: 0.6,
                 dataLabelNudge: 0,
-                dataLabels: ['Longer', 'B', 'C', 'Longerest', 'None']
+                dataLabels: ['Longer', 'B', 'C', 'Longer', 'None']
             }
         },
         legend: {
 <script type="text/javascript">
     $(document).ready(function(){
         
-        $('#code_1').html($('#example_1').text());
-        $('#code_2').html($('#example_2').text());
-        $('#code_3').html($('#example_3').text());
-        $('#code_4').html($('#example_4').text());
+        $('#code_1').html($('#example_1').html());
+        $('#code_2').html($('#example_2').html());
+        $('#code_3').html($('#example_3').html());
+        $('#code_4').html($('#example_4').html());
         $(document).unload(function() {$('*').unbind(); });
 
     });
   </head>
   <body>
 <?php include "nav.inc"; ?>
-<div id="code"></div>
 
     <p>Data labels can be automatically added to pie chart and donut chart slices as well as funnel chart areas.  what labels are displayed is controlled by the series "dataLabel" option.  There are 4 types of data labels to display:<p>
     <ul>

File examples/examples.css

 
 div.nav {
     margin-bottom:10px;
+}
+
+pre.code-block{
+    background: #D8F4DC;
+    border: 1px solid rgb(200, 200, 200);
+    padding-top: 1em;
+    padding-left: 3em;
+    padding-bottom: 1em;
+    margin-top: 1em;
+    margin-bottom: 3em;
+    
 }

File examples/legendLabels.html

   <script language="javascript" type="text/javascript" src="../src/jquery.jqplot.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.enhancedLegendRenderer.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.pieRenderer.js"></script>
+  <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.barRenderer.js"></script>
+  <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.categoryAxisRenderer.js"></script>
   <!-- END: load jqplot -->
 
 <style type="text/css">
         padding: 1px;
         border: 1px solid #dedede;
     }*/
+    
+    pre {
+        background: #D8F4DC;
+        border: 1px solid rgb(200, 200, 200);
+        padding-top: 1em;
+        padding-left: 3em;
+        padding-bottom: 1em;
+        margin-top: 1em;
+        margin-bottom: 3em;
+        
+    }
+    
+    p {
+        margin: 2em 0;
+    }
+    
+    #chart2 .jqplot-table-legend {
+/*        margin-left: 10px;*/
+    }
 </style>
-<script language="javascript" type="text/javascript">
-$(document).ready(function(){
+
+<script id="example_1" type="text/javascript">$(document).ready(function(){
 
    s1 = [1,6,9,8];
    s2 = [4,3,1,2];
 		    yaxis:{min:0, max:35}
 		}
    });
-
-   plot2 = $.jqplot('chart2',[s1, s2, s3, s4, s5, s6],{
-       stackSeries: true,
+});
+</script>
+  
+<script id="example_2" type="text/javascript">$(document).ready(function(){
+    plot2 = $.jqplot('chart2',[s1, s2, s3, s4, s5, s6],{
+        stackSeries: true,
         seriesDefaults: {
-            fill: true,
-            showMarker: false
+            renderer: $.jqplot.BarRenderer
         },
-       legend:{
-           renderer: $.jqplot.EnhancedLegendRenderer,
-           show:true,
-           showLabels: false,
-           labels:['Fog', 'Rain', 'Frost', 'Sleet', 'Hail', 'Snow'],
-           rendererOptions:{
-               numberColumns:2,
-               seriesToggle: 900,
-               disableIEFading: false
-           },
-           placement:'outside'
-		},
-		axes: {
-		    xaxis:{min:1, max:4},
-		    yaxis:{min:0, max:35}
-		}
-   });
-
+        legend:{
+            renderer: $.jqplot.EnhancedLegendRenderer,
+            show:true,
+            showLabels: true,
+            labels:['Fog', 'Rain', 'Frost', 'Sleet', 'Hail', 'Snow'],
+            rendererOptions:{
+                numberColumns:1,
+                seriesToggle: 900,
+                disableIEFading: false
+            },
+            placement:'outside',
+            shrinkGrid: true
+        },
+        axes: {
+            xaxis:{renderer: $.jqplot.CategoryAxisRenderer},
+            yaxis:{min:0, max:35}
+        }
+    });
+});
+</script>
+  
+<script id="example_3" type="text/javascript">$(document).ready(function(){
    plot3 = $.jqplot('chart3',[s1, s2, s3, s4, s5, s6],{
        stackSeries: true,
         seriesDefaults: {
                numberRows:1
            },
            placement:'outside',
-           location:'s'
+           location:'s',
+           marginTop: '30px'
 		},
 		axes: {
 		    xaxis:{min:1, max:4},
 		    yaxis:{min:0, max:35}
 		}
    });
-
+});
+</script>
+  
+<script id="example_4" type="text/javascript">$(document).ready(function(){
     plot4 = $.jqplot('chart4', [[['A',25],['B',14],['C',7],['D', 13],['E', 11],['F',35]]], {
       seriesDefaults:{
           renderer:$.jqplot.PieRenderer
           }
       }      
     });
-    
-    // Another way to position the legend below the chart.
-    $('#chart3 .jqplot-table-legend').css({top: String($('#chart3').height()+15)+'px'});
    
  });
 </script>
+
+<script type="text/javascript">
+    $(document).ready(function(){
+        
+        $('#code_1').html($('#example_1').html());
+        $('#code_2').html($('#example_2').html());
+        $('#code_3').html($('#example_3').html());
+        $('#code_4').html($('#example_4').html());
+        $(document).unload(function() {$('*').unbind(); });
+
+    });
+</script> 
   </head>
   <body>
 <?php include "nav.inc"; ?>
 </ul>
 
 <p>The first plot has legend labels in 3 columns.  They are clickable.</p>
+
 <div id="chart1" class="plot" style="width:500px;height:300px;"></div>
+
+    <pre id="code_1"></pre>
+    
 <p>The second chart has legend labels in 2 columns placed outside of the plot.  The showLabels option is false, but the labels are still clickable.</p>
 <p>The legend renderer's "seriesToggle" option has been set to 900 to produce a slow, 900 ms fade.  You can set this to a number or to 'fast', 'normal' or 'slow'.</p>
 <p>Also, the disableIEFading option is set to false to allow fading on IE (as opposed to simple show/hide).  In IE, series will be toggled with a show()/hide() method by default as opposed to fadeIn()/fadeOut() because of poor performance on some machines.</p>
 <div id="chart2" class="plot" style="width:500px;height:300px;"></div>
+
+    <pre id="code_2"></pre>
+
 <p>The third plot has legend labels in 1 row outside and below the chart area.  The showSwatches option is false, but the labels are still clickable.</p>
 <div id="chart3" class="plot" style="width:500px;height:300px;"></div>
+
+
+    <pre id="code_3"></pre>
 <p>The fourth chart is a pie plot.  Pie plots use their own legend renderer, since a pie plot is only 1 series.  The pie legend renderer has also been updated to handle custom rows/columns, although it is not clickable.</p>
 <div id="chart4" class="plot" style="width:500px;height:300px;"></div>
-<p>
+
+    <pre id="code_4"></pre>
+    
   </body>
 </html>

File examples/mekkoChart.html

         seriesDefaults:{renderer:$.jqplot.MekkoRenderer, rendererOptions: {borderColor: '#dddddd'}},
         legend:{
             show:true, 
-            rendererOptions:{placement: "inside"}, 
+            rendererOptions:{placement: "insideGrid"}, 
             location:'e'
         },
         axesDefaults:{
 <pre>
 legend:{
     show:true, 
-    rendererOptions:{placement: "inside"}, 
+    rendererOptions:{placement: "insideGrid"}, 
     location:'e'
 },
 </pre>

File examples/waterfall.html

 	    font-family:Arial,Helvetica,Sans-serif;
 	  }
   </style>
-  <script type="text/javascript" language="javascript">
-  
-  $(document).ready(function(){
-      $.jqplot.config.enablePlugins = true;
 
-var line1 = [14, 3, 4, -3, 5, 2, -3, -7];
-var ticks = ['2008', 'Apricots', 'Tomatoes', 'Potatoes', 'Rhubarb', 'Squash', 'Grapes', 'Peanuts', '2009'];
+<script id="example_1" type="text/javascript">$(document).ready(function(){
+    var line1 = [14, 3, 4, -3, 5, 2, -3, -7];
+    var ticks = ['2008', 'Apricots', 'Tomatoes', 'Potatoes', 'Rhubarb', 'Squash', 'Grapes', 'Peanuts', '2009'];
 
 
-plot1 = $.jqplot('chart1', [line1], {
-  title: 'Crop Yield Charnge, 2008 to 2009',
-  seriesDefaults:{
-    renderer:$.jqplot.BarRenderer, 
-    rendererOptions:{
-      waterfall:true,
-      varyBarColor: true
-    },
-    pointLabels: {
-      hideZeros: true
-    },
-    yaxis:'y2axis'
-  },
-  axes:{
-    xaxis:{
-      renderer:$.jqplot.CategoryAxisRenderer, 
-      ticks:ticks,
-      tickRenderer: $.jqplot.CanvasAxisTickRenderer,
-      tickOptions: {
-        angle: -90,
-        fontSize: '10pt',
-        showMark: false,
-        showGridline: false
-      }
-    },
-    y2axis: {
-      min: 0,
-      tickInterval: 5
-    }
-  }
-});
+    plot1 = $.jqplot('chart1', [line1], {
+        title: 'Crop Yield Charnge, 2008 to 2009',
+        seriesDefaults:{
+            renderer:$.jqplot.BarRenderer, 
+            rendererOptions:{
+                waterfall:true,
+                varyBarColor: true
+            },
+            pointLabels: {
+                hideZeros: true
+            },
+            yaxis:'y2axis'
+        },
+        axes:{
+            xaxis:{
+                renderer:$.jqplot.CategoryAxisRenderer, 
+                ticks:ticks,
+                tickRenderer: $.jqplot.CanvasAxisTickRenderer,
+                tickOptions: {
+                    angle: -90,
+                    fontSize: '10pt',
+                    showMark: false,
+                    showGridline: false
+                }
+            },
+            y2axis: {
+                min: 0,
+                tickInterval: 5
+            }
+        }
+    });
+});</script>
 
 
-plot2 = $.jqplot('chart2', [line1], {
-  title: 'Crop Yield Charnge, 2008 to 2009',
-  seriesColors:['#333333', '#999999', '#3EA140', '#3EA140', '#3EA140', '#783F16', '#783F16', '#783F16', '#333333'],
-  seriesDefaults:{
-    renderer:$.jqplot.BarRenderer, 
-    rendererOptions:{
-      waterfall:true,
-      varyBarColor: true,
-      useNegativeColors: false
-    },
-    pointLabels: {
-      hideZeros: true
-    },
-    yaxis:'y2axis'
-  },
-  axes:{
-    xaxis:{
-      renderer:$.jqplot.CategoryAxisRenderer, 
-      ticks:ticks,
-      tickRenderer: $.jqplot.CanvasAxisTickRenderer,
-      tickOptions: {
-        angle: -90,
-        fontSize: '10pt',
-        showMark: false,
-        showGridline: false
-      }
-    },
-    y2axis: {
-      min: 0,
-      tickInterval: 5
-    }
-  }
-});
+<script id="example_2" type="text/javascript">$(document).ready(function(){
 
+    var line1 = [14, 3, 4, -3, 5, 2, -3, -7];
+    var ticks = ['2008', 'Apricots', 'Tomatoes', 'Potatoes', 'Rhubarb', 'Squash', 'Grapes', 'Peanuts', '2009'];
+    plot2 = $.jqplot('chart2', [line1], {
+        title: 'Crop Yield Charnge, 2008 to 2009',
+        seriesColors:['#333333', '#999999', '#3EA140', '#3EA140', '#3EA140', '#783F16', '#783F16', '#783F16', '#333333'],
+        seriesDefaults:{
+            renderer:$.jqplot.BarRenderer, 
+            rendererOptions:{
+                waterfall:true,
+                varyBarColor: true,
+                useNegativeColors: false
+            },
+            pointLabels: {
+                hideZeros: true
+            },
+            yaxis:'y2axis'
+        },
+        axes:{
+            xaxis:{
+                renderer:$.jqplot.CategoryAxisRenderer, 
+                ticks:ticks,
+                tickRenderer: $.jqplot.CanvasAxisTickRenderer,
+                tickOptions: {
+                    angle: -90,
+                    fontSize: '10pt',
+                    showMark: false,
+                    showGridline: false
+                }
+            },
+            y2axis: {
+                min: 0,
+                tickInterval: 5
+            }
+        }
+    });
+});</script>
 
-  });
-  </script>
+<script type="text/javascript">
+    $(document).ready(function(){
+        
+        $('#code_1').html($('#example_1').text());
+        $('#code_2').html($('#example_2').text());
+        $(document).unload(function() {$('*').unbind(); });
+
+    });
+</script>
   </head>
   <body>
 <?php include "nav.inc"; ?>
     <p>Waterfall chart using default bar colors.</p>
     <div id="chart1" style="margin-top:20px; margin-left:20px; width:350px; height:350px;"></div>
+    <pre id="code_1" class="code-block"></pre>
     <p>Waterfall chart using custom colors and "useNegativeColors" set to "false".</p>
     <div id="chart2" style="margin-top:20px; margin-left:20px; width:350px; height:350px;"></div>
+    <pre id="code_2" class="code-block"></pre>
   </body>
 </html>

File src/jqplot.core.js

             _options = options;
         }
         var plot = new jqPlot();
+        // remove any error class that may be stuck on target.
+        $('#'+target).removeClass('jqplot-error');
         
         if ($.jqplot.config.catchErrors) {
             try {
             }
             catch(e) {
                 var msg = $.jqplot.config.errorMessage || e.message;
-                $('#'+target).append('<div style="text-align:center;position:relative;top:50%;">'+msg+'</div>');
-                $('#'+target).css({background: $.jqplot.config.errorBackground, border: $.jqplot.config.errorBorder, font: $.jqplot.config.errorFont});
+                $('#'+target).append('<div class="jqplot-error-message">'+msg+'</div>');
+                $('#'+target).addClass('jqplot-error');
+                document.getElementById(target).style.background = $.jqplot.config.errorBackground;
+                document.getElementById(target).style.border = $.jqplot.config.errorBorder;
+                document.getElementById(target).style.fontFamily = $.jqplot.config.errorFontFamily;
+                document.getElementById(target).style.fontSize = $.jqplot.config.errorFontSize;
+                document.getElementById(target).style.fontStyle = $.jqplot.config.errorFontStyle;
+                document.getElementById(target).style.fontWeight = $.jqplot.config.errorFontWeight;
             }
         }
         else {        
             plot.themeEngine.init.call(plot);
             return plot;
         }
-        
     };
         
     $.jqplot.debug = 1;
         errorMessage: '',
         errorBackground: '',
         errorBorder: '',
-        errorFont: '',
+        errorFontFamily: '',
+        errorFontSize: '',
+        errorFontStyle: '',
+        errorFontWeight: '',
         catchErrors: false
     };
     
         // true to show the color swatches on the legend.
         this.showSwatches = true;
         // prop: placement
-        // "inside" places the legend inside of the grid, 
-        // '"outside" places it ouside of the grid.
-        this.placement = "inside";
+        // "insideGrid" places legend inside the grid area of the plot.
+        // "outsideGrid" places the legend outside the grid but inside the plot container, 
+        // shrinking the grid to accomodate the legend.
+        // "inside" synonym for "insideGrid", 
+        // "outside" places the legend ouside the grid area, but does not shrink the grid which
+        // can cause the legend to overflow the plot container.
+        this.placement = "insideGrid";
         // prop: xoffset
-        // offset from the inside edge of the plot in the x direction in pixels.
-        this.xoffset = 12;
+        // DEPRECATED.  Set the margins on the legend using the marginTop, marginLeft, etc. 
+        // properties or via CSS margin styling of the .jqplot-table-legend class.
+        this.xoffset = 0;
         // prop: yoffset
-        // offset from the inside edge of the plot in the y direction in pixels.
-        this.yoffset = 12;
+        // DEPRECATED.  Set the margins on the legend using the marginTop, marginLeft, etc. 
+        // properties or via CSS margin styling of the .jqplot-table-legend class.
+        this.yoffset = 0;
         // prop: border
         // css spec for the border around the legend box.
         this.border;
         this.rendererOptions = {};
         // prop: predraw
         // Wether to draw the legend before the series or not.
+        // Used with series specific legend renderers for pie, donut, mekko charts, etc.
         this.preDraw = false;
+        // prop: marginTop
+        // CSS margin for the legend DOM element. This will set an element 
+        // CSS style for the margin which will override any style sheet setting.
+        // The default will be taken from the stylesheet.
+        this.marginTop = null;
+        // prop: marginRight
+        // CSS margin for the legend DOM element. This will set an element 
+        // CSS style for the margin which will override any style sheet setting.
+        // The default will be taken from the stylesheet.
+        this.marginRight = null;
+        // prop: marginBottom
+        // CSS margin for the legend DOM element. This will set an element 
+        // CSS style for the margin which will override any style sheet setting.
+        // The default will be taken from the stylesheet.
+        this.marginBottom = null;
+        // prop: marginLeft
+        // CSS margin for the legend DOM element. This will set an element 
+        // CSS style for the margin which will override any style sheet setting.
+        // The default will be taken from the stylesheet.
+        this.marginLeft = null;
+        
         this.escapeHtml = false;
         this._series = [];
         
     Legend.prototype = new $.jqplot.ElemContainer();
     Legend.prototype.constructor = Legend;
     
+    Legend.prototype.setOptions = function(options) {
+        $.extend(true, this, options);
+        
+        // Try to emulate deprecated behaviour
+        // if user has specified xoffset or yoffset, copy these to
+        // the margin properties.
+        
+        if (this.placement ==  'inside') this.placement = 'insideGrid';
+        
+        if (this.xoffset >0) {
+            if (this.placement == 'insideGrid') {
+                switch (this.location) {
+                    case 'nw':
+                    case 'w':
+                    case 'sw':
+                        if (this.marginLeft == null) {
+                            this.marginLeft = this.xoffset + 'px';
+                        }
+                        this.marginRight = '0px';
+                        break;
+                    case 'ne':
+                    case 'e':
+                    case 'se':
+                    default:
+                        if (this.marginRight == null) {
+                            this.marginRight = this.xoffset + 'px';
+                        }
+                        this.marginLeft = '0px';
+                        break;
+                }
+            }
+            else if (this.placement == 'outside') {
+                switch (this.location) {
+                    case 'nw':
+                    case 'w':
+                    case 'sw':
+                        if (this.marginRight == null) {
+                            this.marginRight = this.xoffset + 'px';
+                        }
+                        this.marginLeft = '0px';
+                        break;
+                    case 'ne':
+                    case 'e':
+                    case 'se':
+                    default:
+                        if (this.marginLeft == null) {
+                            this.marginLeft = this.xoffset + 'px';
+                        }
+                        this.marginRight = '0px';
+                        break;
+                }
+            }
+            this.xoffset = 0;
+        }
+        
+        if (this.yoffset >0) {
+            if (this.placement == 'outside') {
+                switch (this.location) {
+                    case 'sw':
+                    case 's':
+                    case 'se':
+                        if (this.marginTop == null) {
+                            this.marginTop = this.yoffset + 'px';
+                        }
+                        this.marginBottom = '0px';
+                        break;
+                    case 'ne':
+                    case 'n':
+                    case 'nw':
+                    default:
+                        if (this.marginBottom == null) {
+                            this.marginBottom = this.yoffset + 'px';
+                        }
+                        this.marginTop = '0px';
+                        break;
+                }
+            }
+            else if (this.placement == 'insideGrid') {
+                switch (this.location) {
+                    case 'sw':
+                    case 's':
+                    case 'se':
+                        if (this.marginBottom == null) {
+                            this.marginBottom = this.yoffset + 'px';
+                        }
+                        this.marginTop = '0px';
+                        break;
+                    case 'ne':
+                    case 'n':
+                    case 'nw':
+                    default:
+                        if (this.marginTop == null) {
+                            this.marginTop = this.yoffset + 'px';
+                        }
+                        this.marginBottom = '0px';
+                        break;
+                }
+            }
+            this.yoffset = 0;
+        }
+        
+        // TO-DO:
+        // Handle case where offsets are < 0.
+        //
+    };
+    
     Legend.prototype.init = function() {
         this.renderer = new this.renderer();
         this.renderer.init.call(this, this.rendererOptions);
             
             this.targetId = '#'+target;
             this.target = $('#'+target);
+            // remove any error class that may be stuck on target.
+            this.target.removeClass('jqplot-error');
             if (!this.target.get(0)) {
                 throw "No plot target specified";
             }
                 $.extend(true, this.title, this.options.title);
             }
             this.title._plotWidth = this._width;
-            $.extend(true, this.legend, this.options.legend);
+            this.legend.setOptions(this.options.legend);
             
             for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) {
                 $.jqplot.postParseOptionsHooks[i].call(this, options);
                 this.baseCanvas.setContext();
                 this.target.append(this.title.draw());
                 this.title.pack({top:0, left:0});
+                
+                // make room  for the legend between the grid and the edge.
+                var legendElem = this.legend.draw();
+                
+                var gridPadding = {top:0, left:0, bottom:0, right:0};
+                
+                if (this.legend.placement == "outsideGrid") {
+                    // temporarily append the legend to get dimensions
+                    this.target.append(legendElem);
+                    switch (this.legend.location) {
+                        case 'n':
+                            gridPadding.top += this.legend.getHeight();
+                            break;
+                        case 's':
+                            gridPadding.bottom += this.legend.getHeight();
+                            break;
+                        case 'ne':
+                        case 'e':
+                        case 'se':
+                            gridPadding.right += this.legend.getWidth();
+                            break;
+                        case 'nw':
+                        case 'w':
+                        case 'sw':
+                            gridPadding.left += this.legend.getWidth();
+                            break;
+                        default:  // same as 'ne'
+                            gridPadding.right += this.legend.getWidth();
+                            break;
+                    }
+                    legendElem = legendElem.detach();
+                }
+                
                 for (var name in this.axes) {
                     this.target.append(this.axes[name].draw(this.baseCanvas._ctx));
                     this.axes[name].set();
                 }
                 if (this.axes.yaxis.show) {
-                    this._gridPadding.left = this.axes.yaxis.getWidth();
+                    gridPadding.left = this.axes.yaxis.getWidth();
                 }
                 var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
                 var rapad = [0, 0, 0, 0];
                         gpr += this.axes[ra[n-1]].getWidth();
                     }
                 }
-                if (gpr > this._gridPadding.right) {
-                    this._gridPadding.right = gpr;
+                if (gpr > gridPadding.right) {
+                    gridPadding.right = gpr;
                 }
                 if (this.title.show && this.axes.x2axis.show) {
-                    this._gridPadding.top = this.title.getHeight() + this.axes.x2axis.getHeight();
+                    gridPadding.top = this.title.getHeight() + this.axes.x2axis.getHeight();
                 }
                 else if (this.title.show) {
-                    this._gridPadding.top = this.title.getHeight();
+                    gridPadding.top = this.title.getHeight();
                 }
                 else if (this.axes.x2axis.show) {
-                    this._gridPadding.top = this.axes.x2axis.getHeight();
+                    gridPadding.top = this.axes.x2axis.getHeight();
                 }
                 if (this.axes.xaxis.show) {
-                    this._gridPadding.bottom = this.axes.xaxis.getHeight();
+                    gridPadding.bottom = this.axes.xaxis.getHeight();
                 }
+                
+                // end of gridPadding adjustments.
+                var arr = ['top', 'bottom', 'left', 'right'];
+                for (var n in arr) {
+                    if (gridPadding[arr[n]]) {
+                        this._gridPadding[arr[n]] = gridPadding[arr[n]];
+                    }
+                }
+                
+                // var legendPadding = (false) ? {top:this.title.getHeight(), left: 0, right: 0, bottom: 0} : this._gridPadding;
             
                 this.axes.xaxis.pack({position:'absolute', bottom:0, left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
                 this.axes.yaxis.pack({position:'absolute', top:0, left:0, height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
             
                 // draw legend before series if the series needs to know the legend dimensions.
                 if (this.legend.preDraw) {  
-                    // this.target.append(this.legend.draw());
-                    this.eventCanvas._elem.before(this.legend.draw());
+                    this.eventCanvas._elem.before(legendElem);
                     this.legend.pack(this._gridPadding);
                     if (this.legend._elem) {
                         this.drawSeries({legendInfo:{location:this.legend.location, placement:this.legend.placement, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}});
                 }
                 else {  // draw series before legend
                     this.drawSeries();
-                    $(this.series[this.series.length-1].canvas._elem).after(this.legend.draw());
-                    // this.target.append(this.legend.draw());
+                    $(this.series[this.series.length-1].canvas._elem).after(legendElem);
                     this.legend.pack(this._gridPadding);                
                 }
             

File src/jqplot.tableLegendRenderer.js

             ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
             ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
             ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+            ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+            ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+            ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+            ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
             this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
         
             var pad = false, 
     };
     
     $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) {
-        if (this.show) {
-            // fake a grid for positioning
-            var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+        if (this.show) {       
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
-                        var a = grid._left + this.xoffset;
-                        var b = grid._top + this.yoffset;
+                        var a = offsets.left;
+                        var b = offsets.top;
                         this._elem.css('left', a);
                         this._elem.css('top', b);
                         break;
                     case 'n':
                         var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = grid._top + this.yoffset;
+                        var b = offsets.top;
                         this._elem.css('left', a);
                         this._elem.css('top', b);
                         break;
                     case 'ne':
-                        var a = offsets.right + this.xoffset;
-                        var b = grid._top + this.yoffset;
+                        var a = offsets.right;
+                        var b = offsets.top;
                         this._elem.css({right:a, top:b});
                         break;
                     case 'e':
-                        var a = offsets.right + this.xoffset;
+                        var a = offsets.right;
                         var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
                         this._elem.css({right:a, top:b});
                         break;
                     case 'se':
-                        var a = offsets.right + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
+                        var a = offsets.right;
+                        var b = offsets.bottom;
                         this._elem.css({right:a, bottom:b});
                         break;
                     case 's':
                         var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = offsets.bottom + this.yoffset;
+                        var b = offsets.bottom;
                         this._elem.css({left:a, bottom:b});
                         break;
                     case 'sw':
-                        var a = grid._left + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
+                        var a = offsets.left;
+                        var b = offsets.bottom;
                         this._elem.css({left:a, bottom:b});
                         break;
                     case 'w':
-                        var a = grid._left + this.xoffset;
+                        var a = offsets.left;
                         var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
                         this._elem.css({left:a, top:b});
                         break;
                     default:  // same as 'se'
-                        var a = grid._right - this.xoffset;
-                        var b = grid._bottom + this.yoffset;
+                        var a = offsets.right;
+                        var b = offsets.bottom;
                         this._elem.css({right:a, bottom:b});
                         break;
                 }
                 
             }
-            else {
+            else if (this.placement == 'outside'){
                 switch (this.location) {
                     case 'nw':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
-                        var b = grid._top + this.yoffset;
+                        var a = this._plotDimensions.width - offsets.left;
+                        var b = offsets.top;
                         this._elem.css('right', a);
                         this._elem.css('top', b);
                         break;
                     case 'n':
                         var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = this._plotDimensions.height - grid._top + this.yoffset;
+                        var b = this._plotDimensions.height - offsets.top;
                         this._elem.css('left', a);
                         this._elem.css('bottom', b);
                         break;
                     case 'ne':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
-                        var b = grid._top + this.yoffset;
+                        var a = this._plotDimensions.width - offsets.right;
+                        var b = offsets.top;
                         this._elem.css({left:a, top:b});
                         break;
                     case 'e':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
+                        var a = this._plotDimensions.width - offsets.right;
                         var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
                         this._elem.css({left:a, top:b});
                         break;
                     case 'se':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
+                        var a = this._plotDimensions.width - offsets.right;
+                        var b = offsets.bottom;
                         this._elem.css({left:a, bottom:b});
                         break;
                     case 's':
                         var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
+                        var b = this._plotDimensions.height - offsets.bottom;
                         this._elem.css({left:a, top:b});
                         break;
                     case 'sw':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
+                        var a = this._plotDimensions.width - offsets.left;
+                        var b = offsets.bottom;
                         this._elem.css({right:a, bottom:b});
                         break;
                     case 'w':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
+                        var a = this._plotDimensions.width - offsets.left;
                         var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
                         this._elem.css({right:a, top:b});
                         break;
                     default:  // same as 'se'
-                        var a = grid._right - this.xoffset;
-                        var b = grid._bottom + this.yoffset;
+                        var a = offsets.right;
+                        var b = offsets.bottom;
                         this._elem.css({right:a, bottom:b});
                         break;
                 }
             }
+            else {
+                switch (this.location) {
+                    case 'nw':
+                        this._elem.css({left:0, top:offsets.top});
+                        break;
+                    case 'n':
+                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+                        this._elem.css({left: a, top:offsets.top});
+                        break;
+                    case 'ne':
+                        this._elem.css({right:0, top:offsets.top});
+                        break;
+                    case 'e':
+                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+                        this._elem.css({right:offsets.right, top:b});
+                        break;
+                    case 'se':
+                        this._elem.css({right:offsets.right, bottom:offsets.bottom});
+                        break;
+                    case 's':
+                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
+                        this._elem.css({left: a, bottom:offsets.bottom});
+                        break;
+                    case 'sw':
+                        this._elem.css({left:offsets.left, bottom:offsets.bottom});
+                        break;
+                    case 'w':
+                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
+                        this._elem.css({left:offsets.left, top:b});
+                        break;
+                    default:  // same as 'se'
+                        this._elem.css({right:offsets.right, bottom:offsets.bottom});
+                        break;
+                }
+            }
         } 
     };
 })(jQuery);

File src/jquery.jqplot.css

     position: absolute;
 }
 
+table.jqplot-table-legend {
+    margin-top: 12px;
+    margin-bottom: 12px;
+    margin-left: 12px;
+    margin-right: 12px;
+}
+
 table.jqplot-table-legend, table.jqplot-cursor-legend {
     background-color: rgba(255,255,255,0.6);
     border: 1px solid #cccccc;
 width:1.2em;
 height:0.7em;
 }
+
+.jqplot-error {
+/*   Styles added to the plot target container when there is an error go here.*/
+    text-align: center;
+}
+
+.jqplot-error-message {
+/*    Styling of the custom error message div goes here.*/
+    position: relative;
+    top: 46%;
+    display: inline-block;
+}

File src/plugins/jqplot.donutRenderer.js

         var offy = 0;
         var trans = 1;
         // var colorGenerator = new this.colorGenerator(this.seriesColors);
-        if (options.legendInfo && options.legendInfo.placement == 'inside') {
+        if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
             var li = options.legendInfo;
             switch (li.location) {
                 case 'nw':
         if (this.show) {
             // fake a grid for positioning
             var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
                         var a = grid._left + this.xoffset;

File src/plugins/jqplot.enhancedLegendRenderer.js

     // class $.jqplot.EnhancedLegendRenderer
     // Legend renderer which can specify the number of rows and/or columns in the legend.
     $.jqplot.EnhancedLegendRenderer = function(){
-        //
+        $.jqplot.TableLegendRenderer.call(this);
     };
     
+    $.jqplot.EnhancedLegendRenderer.prototype = new $.jqplot.TableLegendRenderer();
+    $.jqplot.EnhancedLegendRenderer.prototype.constructor = $.jqplot.EnhancedLegendRenderer;
+    
     // called with scope of legend.
     $.jqplot.EnhancedLegendRenderer.prototype.init = function(options) {
         // prop: numberRows
             ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
             ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
             ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
+            ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : '';
+            ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : '';
+            ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : '';
+            ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : '';
             this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
             if (this.seriesToggle) {
                 this._elem.css('z-index', '3');
             this.eventCanvas._elem.after(e);
         }
     };
-    
-    $.jqplot.EnhancedLegendRenderer.prototype.pack = function(offsets) {
-        if (this.show) {
-            // fake a grid for positioning
-            var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
-                switch (this.location) {
-                    case 'nw':
-                        var a = grid._left + this.xoffset;
-                        var b = grid._top + this.yoffset;
-                        this._elem.css('left', a);
-                        this._elem.css('top', b);
-                        break;
-                    case 'n':
-                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = grid._top + this.yoffset;
-                        this._elem.css('left', a);
-                        this._elem.css('top', b);
-                        break;
-                    case 'ne':
-                        var a = offsets.right + this.xoffset;
-                        var b = grid._top + this.yoffset;
-                        this._elem.css({right:a, top:b});
-                        break;
-                    case 'e':
-                        var a = offsets.right + this.xoffset;
-                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
-                        this._elem.css({right:a, top:b});
-                        break;
-                    case 'se':
-                        var a = offsets.right + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
-                        this._elem.css({right:a, bottom:b});
-                        break;
-                    case 's':
-                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = offsets.bottom + this.yoffset;
-                        this._elem.css({left:a, bottom:b});
-                        break;
-                    case 'sw':
-                        var a = grid._left + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
-                        this._elem.css({left:a, bottom:b});
-                        break;
-                    case 'w':
-                        var a = grid._left + this.xoffset;
-                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
-                        this._elem.css({left:a, top:b});
-                        break;
-                    default:  // same as 'se'
-                        var a = grid._right - this.xoffset;
-                        var b = grid._bottom + this.yoffset;
-                        this._elem.css({right:a, bottom:b});
-                        break;
-                }
-                
-            }
-            else {
-                switch (this.location) {
-                    case 'nw':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
-                        var b = grid._top + this.yoffset;
-                        this._elem.css('right', a);
-                        this._elem.css('top', b);
-                        break;
-                    case 'n':
-                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = this._plotDimensions.height - grid._top + this.yoffset;
-                        this._elem.css('left', a);
-                        this._elem.css('bottom', b);
-                        break;
-                    case 'ne':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
-                        var b = grid._top + this.yoffset;
-                        this._elem.css({left:a, top:b});
-                        break;
-                    case 'e':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
-                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
-                        this._elem.css({left:a, top:b});
-                        break;
-                    case 'se':
-                        var a = this._plotDimensions.width - offsets.right + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
-                        this._elem.css({left:a, bottom:b});
-                        break;
-                    case 's':
-                        var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
-                        var b = this._plotDimensions.height - offsets.bottom + this.yoffset;
-                        this._elem.css({left:a, top:b});
-                        break;
-                    case 'sw':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
-                        var b = offsets.bottom + this.yoffset;
-                        this._elem.css({right:a, bottom:b});
-                        break;
-                    case 'w':
-                        var a = this._plotDimensions.width - grid._left + this.xoffset;
-                        var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
-                        this._elem.css({right:a, top:b});
-                        break;
-                    default:  // same as 'se'
-                        var a = grid._right - this.xoffset;
-                        var b = grid._bottom + this.yoffset;
-                        this._elem.css({right:a, bottom:b});
-                        break;
-                }
-            }
-        } 
-    };
 })(jQuery);

File src/plugins/jqplot.funnelRenderer.js

         var trans = 1;
         this._areas = [];
         // var colorGenerator = new this.colorGenerator(this.seriesColors);
-        if (options.legendInfo && options.legendInfo.placement == 'inside') {
+        if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
             var li = options.legendInfo;
             switch (li.location) {
                 case 'nw':
         if (this.show) {
             // fake a grid for positioning
             var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
                         var a = grid._left + this.xoffset;

File src/plugins/jqplot.mekkoRenderer.js

         if (this.show) {
             // fake a grid for positioning
             var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
                         var a = grid._left + this.xoffset;

File src/plugins/jqplot.meterGaugeRenderer.js

         if (this.show) {
             // fake a grid for positioning
             var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
                         var a = grid._left + this.xoffset;

File src/plugins/jqplot.pieRenderer.js

         var offy = 0;
         var trans = 1;
         // var colorGenerator = new this.colorGenerator(this.seriesColors);
-        if (options.legendInfo && options.legendInfo.placement == 'inside') {
+        if (options.legendInfo && options.legendInfo.placement == 'insideGrid') {
             var li = options.legendInfo;
             switch (li.location) {
                 case 'nw':
         if (this.show) {
             // fake a grid for positioning
             var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};        
-            if (this.placement == 'inside') {
+            if (this.placement == 'insideGrid') {
                 switch (this.location) {
                     case 'nw':
                         var a = grid._left + this.xoffset;