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' ] );