1/*
2Plugin Name: amCharts Responsive
3Description: This plugin add responsive functionality to JavaScript Charts and Maps.
4Author: Martynas Majeris, amCharts
5Contributors: Ohad Schneider
6Version: 1.0.2
7Author URI: http://www.amcharts.com/
8
9Copyright 2015 amCharts
10
11Licensed under the Apache License, Version 2.0 (the "License");
12you may not use this file except in compliance with the License.
13You may obtain a copy of the License at
14
15	http://www.apache.org/licenses/LICENSE-2.0
16
17Unless required by applicable law or agreed to in writing, software
18distributed under the License is distributed on an "AS IS" BASIS,
19WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20See the License for the specific language governing permissions and
21limitations under the License.
22
23Please note that the above license covers only this plugin. It by all means does
24not apply to any other amCharts products that are covered by different licenses.
25*/
26
27/*global AmCharts*/
28
29AmCharts.addInitHandler( function( chart ) {
30  "use strict";
31
32  if ( chart.responsive === undefined || chart.responsive.ready === true || chart.responsive.enabled !== true )
33    return;
34
35  var version = chart.version.split( '.' );
36  if ( ( version.length < 2 ) || Number( version[ 0 ] ) < 3 || ( Number( version[ 0 ] ) === 3 && Number( version[ 1 ] ) < 13 ) )
37    return;
38
39  // a short variable for easy reference
40  var r = chart.responsive;
41
42  r.ready = true;
43  r.currentRules = {};
44  r.overridden = [];
45
46  // defaults per chart type
47  var defaults = {
48
49    /**
50     * AmPie
51     */
52    'pie': [
53
54      /**
55       * Disable legend in certain cases
56       */
57      {
58        "maxWidth": 550,
59        "legendPosition": "left",
60        "overrides": {
61          "legend": {
62            "enabled": false
63          }
64        }
65      }, {
66        "maxWidth": 550,
67        "legendPosition": "right",
68        "overrides": {
69          "legend": {
70            "enabled": false
71          }
72        }
73      }, {
74        "maxWidth": 150,
75        "overrides": {
76          "legend": {
77            "enabled": false
78          }
79        }
80      }, {
81        "maxHeight": 350,
82        "legendPosition": "top",
83        "overrides": {
84          "legend": {
85            "enabled": false
86          }
87        }
88      }, {
89        "maxHeight": 350,
90        "legendPosition": "bottom",
91        "overrides": {
92          "legend": {
93            "enabled": false
94          }
95        }
96      }, {
97        "maxHeight": 150,
98        "overrides": {
99          "legend": {
100            "enabled": false
101          }
102        }
103      },
104
105      /**
106       * Narrow chart
107       */
108      {
109        "maxWidth": 400,
110        "overrides": {
111          "labelsEnabled": false
112        }
113      }, {
114        "maxWidth": 100,
115        "overrides": {
116          "legend": {
117            "enabled": false
118          }
119        }
120      },
121
122      /**
123       * Short chart
124       */
125      {
126        "maxHeight": 350,
127        "overrides": {
128          "pullOutRadius": 0
129        }
130      }, {
131        "maxHeight": 200,
132        "overrides": {
133          "titles": {
134            "enabled": false
135          },
136          "labelsEnabled": false
137        }
138      },
139
140      /**
141       * Supersmall
142       */
143      {
144        "maxWidth": 60,
145        "overrides": {
146          "autoMargins": false,
147          "marginTop": 0,
148          "marginBottom": 0,
149          "marginLeft": 0,
150          "marginRight": 0,
151          "radius": "50%",
152          "innerRadius": 0,
153          "balloon": {
154            "enabled": false
155          },
156          "legend": {
157            "enabled": false
158          }
159        }
160      }, {
161        "maxHeight": 60,
162        "overrides": {
163          "marginTop": 0,
164          "marginBottom": 0,
165          "marginLeft": 0,
166          "marginRight": 0,
167          "radius": "50%",
168          "innerRadius": 0,
169          "balloon": {
170            "enabled": false
171          },
172          "legend": {
173            "enabled": false
174          }
175        }
176      }
177    ],
178
179    /**
180     * AmFunnel
181     */
182
183    'funnel': [ {
184      "maxWidth": 550,
185      "legendPosition": "left",
186      "overrides": {
187        "legend": {
188          "enabled": false
189        }
190      }
191    }, {
192      "maxWidth": 550,
193      "legendPosition": "right",
194      "overrides": {
195        "legend": {
196          "enabled": false
197        }
198      }
199    }, {
200      "maxWidth": 150,
201      "overrides": {
202        "legend": {
203          "enabled": false
204        }
205      }
206    }, {
207      "maxHeight": 500,
208      "legendPosition": "top",
209      "overrides": {
210        "legend": {
211          "enabled": false
212        }
213      }
214    }, {
215      "maxHeight": 500,
216      "legendPosition": "bottom",
217      "overrides": {
218        "legend": {
219          "enabled": false
220        }
221      }
222    }, {
223      "maxHeight": 150,
224      "overrides": {
225        "legend": {
226          "enabled": false
227        }
228      }
229    }, {
230      "maxWidth": 400,
231      "overrides": {
232        "labelsEnabled": false,
233        "marginLeft": 10,
234        "marginRight": 10,
235        "legend": {
236          "enabled": false
237        }
238      }
239    }, {
240      "maxHeight": 350,
241      "overrides": {
242        "pullOutRadius": 0,
243        "legend": {
244          "enabled": false
245        }
246      }
247    }, {
248      "maxHeight": 300,
249      "overrides": {
250        "titles": {
251          "enabled": false
252        }
253      }
254    } ],
255
256    /**
257     * AmRadar
258     */
259
260    "radar": [ {
261      "maxWidth": 550,
262      "legendPosition": "left",
263      "overrides": {
264        "legend": {
265          "enabled": false
266        }
267      }
268    }, {
269      "maxWidth": 550,
270      "legendPosition": "right",
271      "overrides": {
272        "legend": {
273          "enabled": false
274        }
275      }
276    }, {
277      "maxWidth": 150,
278      "overrides": {
279        "legend": {
280          "enabled": false
281        }
282      }
283    }, {
284      "maxHeight": 350,
285      "legendPosition": "top",
286      "overrides": {
287        "legend": {
288          "enabled": false
289        }
290      }
291    }, {
292      "maxHeight": 350,
293      "legendPosition": "bottom",
294      "overrides": {
295        "legend": {
296          "enabled": false
297        }
298      }
299    }, {
300      "maxHeight": 150,
301      "overrides": {
302        "legend": {
303          "enabled": false
304        }
305      }
306    }, {
307      "maxWidth": 300,
308      "overrides": {
309        "labelsEnabled": false
310      }
311    }, {
312      "maxWidth": 200,
313      "overrides": {
314        "autoMargins": false,
315        "marginTop": 0,
316        "marginBottom": 0,
317        "marginLeft": 0,
318        "marginRight": 0,
319        "radius": "50%",
320        "titles": {
321          "enabled": false
322        },
323        "valueAxes": {
324          "labelsEnabled": false,
325          "radarCategoriesEnabled": false
326        }
327      }
328    }, {
329      "maxHeight": 300,
330      "overrides": {
331        "labelsEnabled": false
332      }
333    }, {
334      "maxHeight": 200,
335      "overrides": {
336        "autoMargins": false,
337        "marginTop": 0,
338        "marginBottom": 0,
339        "marginLeft": 0,
340        "marginRight": 0,
341        "radius": "50%",
342        "titles": {
343          "enabled": false
344        },
345        "valueAxes": {
346          "radarCategoriesEnabled": false
347        }
348      }
349    }, {
350      "maxHeight": 100,
351      "overrides": {
352        "valueAxes": {
353          "labelsEnabled": false
354        }
355      }
356    } ],
357
358    /**
359     * AmGauge
360     */
361
362    'gauge': [ {
363      "maxWidth": 550,
364      "legendPosition": "left",
365      "overrides": {
366        "legend": {
367          "enabled": false
368        }
369      }
370    }, {
371      "maxWidth": 550,
372      "legendPosition": "right",
373      "overrides": {
374        "legend": {
375          "enabled": false
376        }
377      }
378    }, {
379      "maxWidth": 150,
380      "overrides": {
381        "legend": {
382          "enabled": false
383        }
384      }
385    }, {
386      "maxHeight": 500,
387      "legendPosition": "top",
388      "overrides": {
389        "legend": {
390          "enabled": false
391        }
392      }
393    }, {
394      "maxHeight": 500,
395      "legendPosition": "bottom",
396      "overrides": {
397        "legend": {
398          "enabled": false
399        }
400      }
401    }, {
402      "maxHeight": 150,
403      "overrides": {
404        "legend": {
405          "enabled": false
406        }
407      }
408    }, {
409      "maxWidth": 200,
410      "overrides": {
411        "titles": {
412          "enabled": false
413        },
414        "allLabels": {
415          "enabled": false
416        },
417        "axes": {
418          "labelsEnabled": false
419        }
420      }
421    }, {
422      "maxHeight": 200,
423      "overrides": {
424        "titles": {
425          "enabled": false
426        },
427        "allLabels": {
428          "enabled": false
429        },
430        "axes": {
431          "labelsEnabled": false
432        }
433      }
434    } ],
435
436    /**
437     * AmSerial
438     */
439    "serial": [
440
441      /**
442       * Disable legend in certain cases
443       */
444      {
445        "maxWidth": 550,
446        "legendPosition": "left",
447        "overrides": {
448          "legend": {
449            "enabled": false
450          }
451        }
452      }, {
453        "maxWidth": 550,
454        "legendPosition": "right",
455        "overrides": {
456          "legend": {
457            "enabled": false
458          }
459        }
460      }, {
461        "maxWidth": 100,
462        "overrides": {
463          "legend": {
464            "enabled": false
465          }
466        }
467      }, {
468        "maxHeight": 350,
469        "legendPosition": "top",
470        "overrides": {
471          "legend": {
472            "enabled": false
473          }
474        }
475      }, {
476        "maxHeight": 350,
477        "legendPosition": "bottom",
478        "overrides": {
479          "legend": {
480            "enabled": false
481          }
482        }
483      }, {
484        "maxHeight": 100,
485        "overrides": {
486          "legend": {
487            "enabled": false
488          }
489        }
490      },
491
492
493      /**
494       * Narrow chart
495       */
496      {
497        "maxWidth": 350,
498        "overrides": {
499          "autoMarginOffset": 0,
500          "graphs": {
501            "hideBulletsCount": 10
502          }
503        }
504      }, {
505        "maxWidth": 350,
506        "rotate": false,
507        "overrides": {
508          "marginLeft": 10,
509          "marginRight": 10,
510          "valueAxes": {
511            "ignoreAxisWidth": true,
512            "inside": true,
513            "title": "",
514            "showFirstLabel": false,
515            "showLastLabel": false
516          },
517          "graphs": {
518            "bullet": "none"
519          }
520        }
521      }, {
522        "maxWidth": 350,
523        "rotate": true,
524        "overrides": {
525          "marginLeft": 10,
526          "marginRight": 10,
527          "categoryAxis": {
528            "ignoreAxisWidth": true,
529            "inside": true,
530            "title": ""
531          }
532        }
533      }, {
534        "maxWidth": 200,
535        "rotate": false,
536        "overrides": {
537          "marginLeft": 10,
538          "marginRight": 10,
539          "marginTop": 10,
540          "marginBottom": 10,
541          "categoryAxis": {
542            "ignoreAxisWidth": true,
543            "labelsEnabled": false,
544            "inside": true,
545            "title": "",
546            "guides": {
547              "inside": true
548            }
549          },
550          "valueAxes": {
551            "ignoreAxisWidth": true,
552            "labelsEnabled": false,
553            "axisAlpha": 0,
554            "guides": {
555              "label": ""
556            }
557          },
558          "legend": {
559            "enabled": false
560          }
561        }
562      }, {
563        "maxWidth": 200,
564        "rotate": true,
565        "overrides": {
566          "chartScrollbar": {
567            "scrollbarHeight": 4,
568            "graph": "",
569            "resizeEnabled": false
570          },
571          "categoryAxis": {
572            "labelsEnabled": false,
573            "axisAlpha": 0,
574            "guides": {
575              "label": ""
576            }
577          },
578          "legend": {
579            "enabled": false
580          }
581        }
582      }, {
583        "maxWidth": 100,
584        "rotate": false,
585        "overrides": {
586          "valueAxes": {
587            "gridAlpha": 0
588          }
589        }
590      }, {
591        "maxWidth": 100,
592        "rotate": true,
593        "overrides": {
594          "categoryAxis": {
595            "gridAlpha": 0
596          }
597        }
598      },
599
600      /**
601       * Short chart
602       */
603      {
604        "maxHeight": 300,
605        "overrides": {
606          "autoMarginOffset": 0,
607          "graphs": {
608            "hideBulletsCount": 10
609          }
610        }
611      }, {
612        "maxHeight": 200,
613        "rotate": false,
614        "overrides": {
615          "marginTop": 10,
616          "marginBottom": 10,
617          "categoryAxis": {
618            "ignoreAxisWidth": true,
619            "inside": true,
620            "title": "",
621            "showFirstLabel": false,
622            "showLastLabel": false
623          }
624        }
625      }, {
626        "maxHeight": 200,
627        "rotate": true,
628        "overrides": {
629          "marginTop": 10,
630          "marginBottom": 10,
631          "valueAxes": {
632            "ignoreAxisWidth": true,
633            "inside": true,
634            "title": "",
635            "showFirstLabel": false,
636            "showLastLabel": false
637          },
638          "graphs": {
639            "bullet": "none"
640          }
641        }
642      }, {
643        "maxHeight": 150,
644        "rotate": false,
645        "overrides": {
646          "titles": {
647            "enabled": false
648          },
649          "chartScrollbar": {
650            "scrollbarHeight": 4,
651            "graph": "",
652            "resizeEnabled": false
653          },
654          "categoryAxis": {
655            "labelsEnabled": false,
656            "ignoreAxisWidth": true,
657            "axisAlpha": 0,
658            "guides": {
659              "label": ""
660            }
661          }
662        }
663      }, {
664        "maxHeight": 150,
665        "rotate": true,
666        "overrides": {
667          "titles": {
668            "enabled": false
669          },
670          "valueAxes": {
671            "labelsEnabled": false,
672            "ignoreAxisWidth": true,
673            "axisAlpha": 0,
674            "guides": {
675              "label": ""
676            }
677          }
678        }
679      }, {
680        "maxHeight": 100,
681        "rotate": false,
682        "overrides": {
683          "valueAxes": {
684            "labelsEnabled": false,
685            "ignoreAxisWidth": true,
686            "axisAlpha": 0,
687            "gridAlpha": 0,
688            "guides": {
689              "label": ""
690            }
691          }
692        }
693      }, {
694        "maxHeight": 100,
695        "rotate": true,
696        "overrides": {
697          "categoryAxis": {
698            "labelsEnabled": false,
699            "ignoreAxisWidth": true,
700            "axisAlpha": 0,
701            "gridAlpha": 0,
702            "guides": {
703              "label": ""
704            }
705          }
706        }
707      },
708
709      /**
710       * Really small charts: microcharts and sparklines
711       */
712      {
713        "maxWidth": 100,
714        "overrides": {
715          "autoMargins": false,
716          "marginTop": 0,
717          "marginBottom": 0,
718          "marginLeft": 0,
719          "marginRight": 0,
720          "categoryAxis": {
721            "labelsEnabled": false
722          },
723          "valueAxes": {
724            "labelsEnabled": false
725          }
726        }
727      }, {
728        "maxHeight": 100,
729        "overrides": {
730          "autoMargins": false,
731          "marginTop": 0,
732          "marginBottom": 0,
733          "marginLeft": 0,
734          "marginRight": 0,
735          "categoryAxis": {
736            "labelsEnabled": false
737          },
738          "valueAxes": {
739            "labelsEnabled": false
740          }
741        }
742      }
743    ],
744
745    /**
746     * AmXY
747     */
748    "xy": [
749
750      /**
751       * Disable legend in certain cases
752       */
753      {
754        "maxWidth": 550,
755        "legendPosition": "left",
756        "overrides": {
757          "legend": {
758            "enabled": false
759          }
760        }
761      }, {
762        "maxWidth": 550,
763        "legendPosition": "right",
764        "overrides": {
765          "legend": {
766            "enabled": false
767          }
768        }
769      }, {
770        "maxWidth": 100,
771        "overrides": {
772          "legend": {
773            "enabled": false
774          }
775        }
776      }, {
777        "maxHeight": 350,
778        "legendPosition": "top",
779        "overrides": {
780          "legend": {
781            "enabled": false
782          }
783        }
784      }, {
785        "maxHeight": 350,
786        "legendPosition": "bottom",
787        "overrides": {
788          "legend": {
789            "enabled": false
790          }
791        }
792      }, {
793        "maxHeight": 100,
794        "overrides": {
795          "legend": {
796            "enabled": false
797          }
798        }
799      },
800
801      /**
802       * Narrow chart
803       */
804      {
805        "maxWidth": 250,
806        "overrides": {
807          "autoMarginOffset": 0,
808          "autoMargins": false,
809          "marginTop": 0,
810          "marginBottom": 0,
811          "marginLeft": 0,
812          "marginRight": 0,
813          "valueAxes": {
814            "inside": true,
815            "title": "",
816            "showFirstLabel": false,
817            "showLastLabel": false
818          },
819          "legend": {
820            "enabled": false
821          }
822        }
823      }, {
824        "maxWidth": 150,
825        "overrides": {
826          "valueyAxes": {
827            "labelsEnabled": false,
828            "axisAlpha": 0,
829            "gridAlpha": 0,
830            "guides": {
831              "label": ""
832            }
833          }
834        }
835      },
836
837      /**
838       * Short chart
839       */
840      {
841        "maxHeight": 250,
842        "overrides": {
843          "autoMarginOffset": 0,
844          "autoMargins": false,
845          "marginTop": 0,
846          "marginBottom": 0,
847          "marginLeft": 0,
848          "marginRight": 0,
849          "valueAxes": {
850            "inside": true,
851            "title": "",
852            "showFirstLabel": false,
853            "showLastLabel": false
854          },
855          "legend": {
856            "enabled": false
857          }
858        }
859      }, {
860        "maxWidth": 150,
861        "overrides": {
862          "valueyAxes": {
863            "labelsEnabled": false,
864            "axisAlpha": 0,
865            "gridAlpha": 0,
866            "guides": {
867              "label": ""
868            }
869          }
870        }
871      }
872    ],
873
874    /**
875     * AmStock
876     */
877
878    'stock': [ {
879      "maxWidth": 500,
880      "overrides": {
881        "dataSetSelector": {
882          "position": "top"
883        },
884        "periodSelector": {
885          "position": "bottom"
886        }
887      }
888    }, {
889      "maxWidth": 400,
890      "overrides": {
891        "dataSetSelector": {
892          "selectText": "",
893          "compareText": ""
894        },
895        "periodSelector": {
896          "periodsText": "",
897          "inputFieldsEnabled": false
898        }
899      }
900    } ],
901
902    /**
903     * AmMap
904     */
905
906    'map': [ {
907      "maxWidth": 200,
908      "overrides": {
909        "zoomControl": {
910          "zoomControlEnabled": false
911        },
912        "smallMap": {
913          "enabled": false
914        },
915        "valueLegend": {
916          "enabled": false
917        },
918        "dataProvider": {
919          "areas": {
920            "descriptionWindowWidth": 160,
921            "descriptionWindowRight": 10,
922            "descriptionWindowTop": 10
923          },
924          "images": {
925            "descriptionWindowWidth": 160,
926            "descriptionWindowRight": 10,
927            "descriptionWindowTop": 10
928          },
929          "lines": {
930            "descriptionWindowWidth": 160,
931            "descriptionWindowRight": 10,
932            "descriptionWindowTop": 10
933          }
934        }
935      }
936    }, {
937      "maxWidth": 150,
938      "overrides": {
939        "dataProvider": {
940          "areas": {
941            "descriptionWindowWidth": 110,
942            "descriptionWindowRight": 10,
943            "descriptionWindowTop": 10
944          },
945          "images": {
946            "descriptionWindowWidth": 110,
947            "descriptionWindowRight": 10,
948            "descriptionWindowTop": 10
949          },
950          "lines": {
951            "descriptionWindowWidth": 110,
952            "descriptionWindowLeft": 10,
953            "descriptionWindowRight": 10
954          }
955        }
956      }
957    }, {
958      "maxHeight": 200,
959      "overrides": {
960        "zoomControl": {
961          "zoomControlEnabled": false
962        },
963        "smallMap": {
964          "enabled": false
965        },
966        "valueLegend": {
967          "enabled": false
968        },
969        "dataProvider": {
970          "areas": {
971            "descriptionWindowHeight": 160,
972            "descriptionWindowRight": 10,
973            "descriptionWindowTop": 10
974          },
975          "images": {
976            "descriptionWindowHeight": 160,
977            "descriptionWindowRight": 10,
978            "descriptionWindowTop": 10
979          },
980          "lines": {
981            "descriptionWindowHeight": 160,
982            "descriptionWindowRight": 10,
983            "descriptionWindowTop": 10
984          }
985        }
986      }
987    }, {
988      "maxHeight": 150,
989      "overrides": {
990        "dataProvider": {
991          "areas": {
992            "descriptionWindowHeight": 110,
993            "descriptionWindowRight": 10,
994            "descriptionWindowTop": 10
995          },
996          "images": {
997            "descriptionWindowHeight": 110,
998            "descriptionWindowRight": 10,
999            "descriptionWindowTop": 10
1000          },
1001          "lines": {
1002            "descriptionWindowHeight": 110,
1003            "descriptionWindowLeft": 10,
1004            "descriptionWindowRight": 10
1005          }
1006        }
1007      }
1008    } ]
1009  };
1010
1011  var isNullOrUndefined = function( obj ) {
1012    return ( obj === null ) || ( obj === undefined );
1013  };
1014
1015  var isArray = function( obj ) {
1016    return ( !isNullOrUndefined( obj ) && Object.prototype.toString.call( obj ) === '[object Array]' );
1017  };
1018
1019  var isObject = function( obj ) {
1020    return ( obj !== null && typeof obj === 'object' ); //the null check is necessary - recall that typeof null === 'object' !
1021  };
1022
1023  var findArrayObjectById = function( arr, id ) {
1024    for ( var i = 0; i < arr.length; i++ ) {
1025      if ( isObject( arr[ i ] ) && arr[ i ].id === id )
1026        return arr[ i ];
1027    }
1028    return undefined; //we can use undefined as it doesn't have an Id property and so will never be the desired object from the array
1029  };
1030
1031  var cloneWithoutPrototypes = function( obj ) {
1032    if ( !isObject( obj ) ) {
1033      return obj;
1034    }
1035
1036    if ( isArray( obj ) ) {
1037      return obj.slice(); //effectively clones the array
1038    }
1039
1040    var clone = {}; //here is where we lose the prototype
1041    for ( var property in obj ) {
1042      if ( Object.prototype.hasOwnProperty.call( obj, property ) ) {
1043        clone[ property ] = cloneWithoutPrototypes( obj[ property ] );
1044      }
1045    }
1046    return clone;
1047  };
1048
1049  var originalValueRetainerPrefix = '{F0578839-A214-4E2D-8D1B-44941ECE8332}_';
1050  var noOriginalPropertyStub = {};
1051
1052  var overrideProperty = function( object, property, overrideValue ) {
1053
1054    var originalValueRetainerProperty = originalValueRetainerPrefix + property;
1055    if ( !( originalValueRetainerProperty in object ) ) {
1056      object[ originalValueRetainerProperty ] = ( property in object ) ? object[ property ] : noOriginalPropertyStub;
1057    }
1058
1059    object[ property ] = cloneWithoutPrototypes( overrideValue );
1060
1061    r.overridden.push( {
1062      object: object,
1063      property: property
1064    } );
1065  };
1066
1067  var restoreOriginalProperty = function( object, property ) {
1068    var originalValue = object[ originalValueRetainerPrefix + property ];
1069    if ( originalValue === noOriginalPropertyStub ) {
1070      delete object[ property ];
1071    } else {
1072      object[ property ] = originalValue;
1073    }
1074  };
1075
1076  var restoreOriginals = function() {
1077    while ( r.overridden.length > 0 ) {
1078      var override = r.overridden.pop();
1079      restoreOriginalProperty( override.object, override.property );
1080    }
1081  };
1082
1083  var redrawChart = function() {
1084    chart.dataChanged = true;
1085    if ( chart.type !== 'xy' ) {
1086      chart.marginsUpdated = false;
1087    }
1088    chart.zoomOutOnDataUpdate = false;
1089    chart.validateNow( true );
1090    restoreOriginalProperty( chart, 'zoomOutOnDataUpdate' );
1091  };
1092
1093  var applyConfig = function( current, override ) {
1094    if ( isNullOrUndefined( override ) ) {
1095      return;
1096    }
1097
1098    for ( var property in override ) {
1099      if ( !Object.prototype.hasOwnProperty.call( override, property ) ) {
1100        continue;
1101      }
1102
1103      var currentValue = current[ property ];
1104      var overrideValue = override[ property ];
1105
1106      //property doesn't exist on current object or it exists as null/undefined => completely override it
1107      if ( isNullOrUndefined( currentValue ) ) {
1108        overrideProperty( current, property, overrideValue );
1109        continue;
1110      }
1111
1112      //current value is an array => override method depends on override form
1113      if ( isArray( currentValue ) ) {
1114
1115        //override value is an array => override method depends on array elements
1116        if ( isArray( overrideValue ) ) {
1117
1118          //current value is an array of non-objects => override the entire array
1119          //we assume a uniformly-typed array, so checking the first value should suffice
1120          if ( ( currentValue.length > 0 && !isObject( currentValue[ 0 ] ) ) || ( overrideValue.length > 0 && !isObject( overrideValue[ 0 ] ) ) ) {
1121            overrideProperty( current, property, overrideValue );
1122            continue;
1123          }
1124
1125          var idPresentOnAllOverrideElements = true;
1126          for ( var k = 0; k < overrideValue.length; k++ ) {
1127            if ( isNullOrUndefined( overrideValue[ k ] ) || isNullOrUndefined( overrideValue[ k ].id ) ) {
1128              idPresentOnAllOverrideElements = false;
1129              break;
1130            }
1131          }
1132
1133          //Id property is present on all override elements => override elements by ID
1134          if ( idPresentOnAllOverrideElements ) {
1135            for ( var i = 0; i < overrideValue.length; i++ ) {
1136              var correspondingCurrentElement = findArrayObjectById( currentValue, overrideValue[ i ].id );
1137              if ( correspondingCurrentElement === undefined ) {
1138                throw ( 'could not find element to override in "' + property + '" with ID: ' + overrideValue[ i ].id );
1139              }
1140              applyConfig( correspondingCurrentElement, overrideValue[ i ] );
1141            }
1142            continue;
1143          }
1144
1145          //Id property is not set on all override elements and there aren't too many overrides => override objects by their index
1146          if ( overrideValue.length <= currentValue.length ) {
1147            for ( var l = 0; l < overrideValue.length; l++ ) {
1148              applyConfig( currentValue[ l ], overrideValue[ l ] );
1149            }
1150            continue;
1151          }
1152
1153          throw 'too many index-based overrides specified for object array property: ' + property;
1154        }
1155
1156        // override value is a single object => override all current array objects with that object
1157        if ( isObject( overrideValue ) ) {
1158          for ( var j = 0; j < currentValue.length; j++ ) {
1159            applyConfig( currentValue[ j ], overrideValue );
1160          }
1161          continue;
1162        }
1163
1164        throw ( 'non-object override detected for array property: ' + property );
1165      }
1166
1167      if ( isObject( currentValue ) ) {
1168        applyConfig( currentValue, overrideValue );
1169        continue;
1170      }
1171
1172      //if we reached this point, the property is defined on the current object but is not an object => override it
1173      overrideProperty( current, property, overrideValue );
1174    }
1175  };
1176
1177  var checkRules = function() {
1178
1179    var width = chart.divRealWidth;
1180    var height = chart.divRealHeight;
1181
1182    // do nothing if the container is hidden (has no size)
1183    if ( width === 0 || height === 0 )
1184      return;
1185
1186    // update current rules
1187    var rulesChanged = false;
1188    for ( var i = 0; i < r.rules.length; i++ ) {
1189      var rule = r.rules[ i ];
1190
1191      var ruleMatches =
1192        ( rule.minWidth === undefined || ( rule.minWidth <= width ) ) && ( rule.maxWidth === undefined || ( rule.maxWidth >= width ) ) &&
1193        ( rule.minHeight === undefined || ( rule.minHeight <= height ) ) && ( rule.maxHeight === undefined || ( rule.maxHeight >= height ) ) &&
1194        ( rule.rotate === undefined || ( rule.rotate === true && chart.rotate === true ) || ( rule.rotate === false && ( chart.rotate === undefined || chart.rotate === false ) ) ) &&
1195        ( rule.legendPosition === undefined || ( chart.legend !== undefined && chart.legend.position !== undefined && chart.legend.position === rule.legendPosition ) );
1196
1197      if ( ruleMatches ) {
1198        if ( r.currentRules[ i ] === undefined ) {
1199          r.currentRules[ i ] = true;
1200          rulesChanged = true;
1201        }
1202      } else if ( r.currentRules[ i ] !== undefined ) {
1203        r.currentRules[ i ] = undefined;
1204        rulesChanged = true;
1205      }
1206    }
1207
1208    if ( !rulesChanged )
1209      return;
1210
1211    restoreOriginals();
1212
1213    for ( var key in r.currentRules ) {
1214      if ( !Object.prototype.hasOwnProperty.call( r.currentRules, key ) ) {
1215        continue;
1216      }
1217
1218      if ( r.currentRules[ key ] !== undefined ) {
1219        if ( isNullOrUndefined( r.rules[ key ] ) ) {
1220          throw 'null or undefined rule in index: ' + key;
1221        }
1222        applyConfig( chart, r.rules[ key ].overrides );
1223      }
1224    }
1225
1226    // TODO - re-apply zooms/slices as necessary
1227
1228    redrawChart();
1229  };
1230
1231  defaults.gantt = defaults.serial;
1232
1233  if ( !isArray( r.rules ) ) {
1234    r.rules = defaults[ chart.type ];
1235  } else if ( r.addDefaultRules !== false ) {
1236    r.rules = defaults[ chart.type ].concat( r.rules );
1237  }
1238
1239  //retain original zoomOutOnDataUpdate value
1240  overrideProperty( chart, 'zoomOutOnDataUpdate', chart.zoomOutOnDataUpdate );
1241
1242  chart.addListener( 'resized', checkRules );
1243  chart.addListener( 'init', checkRules );
1244
1245}, [ 'pie', 'serial', 'xy', 'funnel', 'radar', 'gauge', 'gantt', 'stock', 'map' ] );