1 2 /** 3 * @fileoverview A base class of all visualization charts. 4 * @version 1.0.1 5 * @see https://google.github.io/styleguide/jsguide.html 6 * @see https://github.com/google/closure-compiler/wiki 7 */ 8 9 10 11 /** 12 * A base class of all visualization charts. 13 * @param {string|Element} container The HTML container. 14 * @constructor 15 * @class A base class of all visualization charts. 16 * @requires charts.Tooltip 17 * @requires util.Object 18 */ 19 charts.BaseChart = function(container) { 20 21 /** 22 * Defaults chart options. 23 * @dict 24 * @see charts.BaseChart#getOptions 25 * @example <code>{ 26 * 'font': {'family': 'Arial', 'size': 13}, 27 * 'opacity': 0.8, 28 * 'colors': [list of colors] 29 * }</code> 30 */ 31 this.defaults = { 32 'font': {'family': 'Arial', 'size': 13}, 33 'opacity': 0.7, 34 'colors': charts.BaseChart.DEFAULT_COLORS 35 }; 36 37 /** 38 * The reference to HTML chart container. 39 * @type {Element} 40 */ 41 this.container = typeof container == 'string' ? 42 dom.getElementById(container) : container; 43 44 /** 45 * Instance of <code>charts.Tooltip</code>. 46 * @type {!charts.Tooltip} 47 * @see charts.Tooltip 48 * @protected 49 */ 50 this.tooltip = new charts.Tooltip; 51 52 /** 53 * Draws the chart based on <code>data</code> and <code>opt_options</code>. 54 * Abstract method, should be overwritten in nested classes. 55 * All overwritten methods should be exported for closure compiler. 56 * @param {!Array.<Array>} data A chart data. 57 * @param {Object=} opt_options A optional chart's configuration options. 58 */ 59 this.draw = function(data, opt_options) {}; 60 61 /** 62 * Gets chart's options merged with defaults chart's options. 63 * @param {Object.<string, *>=} opt_options Options map. 64 * @return {!Object.<string, *>} A map of name/value pairs. 65 * @see charts.BaseChart#defaults 66 */ 67 this.getOptions = function(opt_options) { 68 return util.Object.extend(self_.defaults, opt_options || {}); 69 }; 70 71 /** 72 * Extracts columns from <code>data</code>. 73 * @param {Array.<Array>} data The chart data. 74 * @return {!Array.<string>} Returns data columns. 75 */ 76 this.getDataColumns = function(data) { 77 // Return copy of first data row. 78 return /** @type {!Array.<string>} */ (data[0].slice()); 79 }; 80 81 /** 82 * Extracts rows from <code>data</code>. 83 * @param {Array.<Array>} data The chart data. 84 * @return {!Array.<Array>} Returns cloned <code>data</code> rows. 85 */ 86 this.getDataRows = function(data) { 87 // Return copy of data rows except first row. 88 return data.slice(1); 89 }; 90 91 /** 92 * Gets data range with min and max values. 93 * @param {Array.<Array>} data The chart data. 94 * @param {number=} opt_column Optional columns index starting from. 95 * @return {!Array.<number>} Returns range as <code>[min, max]</code> array. 96 */ 97 this.getDataRange = function(data, opt_column) { 98 if (!data.range_) { 99 opt_column = opt_column || 0; 100 /** @type {!Array.<Array>} */ var rows = self_.getDataRows(data); 101 /** @type {number} */ var maxValue = 0; 102 /** @type {?number} */ var minValue = null; 103 for (/** @type {number} */ var i = 0; i < rows.length;) { 104 /** @type {Array.<number>} */ var row = rows[i++]; 105 for (/** @type {number} */ var j = opt_column; j < row.length; j++) { 106 maxValue = Math.max(maxValue, row[j]); 107 if (minValue == null) minValue = maxValue; 108 minValue = Math.min(minValue, row[j]); 109 } 110 } 111 data.range_ = [minValue, maxValue]; 112 } 113 return data.range_; 114 }; 115 116 /** 117 * Gets max value. 118 * @param {Array.<Array>} data The chart data. 119 * @return {number} Returns max value. 120 */ 121 this.getMaxValue = function(data) { 122 return self_.getDataRange(data)[1]; 123 }; 124 125 /** 126 * Gets min value. 127 * @param {Array.<Array>} data The chart data. 128 * @return {number} Returns min value. 129 */ 130 this.getMinValue = function(data) { 131 return self_.getDataRange(data)[0]; 132 }; 133 134 /** 135 * Draws content into <code>this.container</code> as <code>innerHTML</code>. 136 * @param {string} content SVG or VML markup content. 137 * @param {number=} opt_width Optional chart width. 138 * @param {number=} opt_height Optional chart height. 139 */ 140 this.drawContent = function(content, opt_width, opt_height) { 141 opt_width = opt_width || self_.container.offsetWidth || 200; 142 opt_height = opt_height || self_.container.offsetHeight || opt_width; 143 144 self_.container.style.position = 'relative'; 145 self_.container.style.overflow = 'hidden'; 146 147 self_.container.innerHTML += (charts.IS_SVG_SUPPORTED ? 148 wrapSvgContent_ : wrapVmlContent_)(content, opt_width, opt_height); 149 }; 150 151 /** 152 * Wraps SVG markup content into <code><svg></code> container. 153 * @param {string} content SVG markup content. 154 * @param {number} width The chart width. 155 * @param {number} height The chart height. 156 * @return {string} Returns wrapped SVG markup. 157 * @private 158 */ 159 function wrapSvgContent_(content, width, height) { 160 // style="shape-rendering:geometricPrecision; 161 // text-rendering:geometricPrecision; 162 // image-rendering:optimizeQuality; 163 // fill-rule:evenodd; 164 // clip-rule:evenodd" 165 return '<svg width="' + width + '" height="' + height + '" version="1.0" ' + 166 'xmlns="http://www.w3.org/2000/svg" ' + 167 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + 168 'style="position:absolute">' + 169 content + '</svg>'; 170 } 171 172 /** 173 * Wraps VML markup content into <code><vml:group></code> container. 174 * @param {string} content VML markup content. 175 * @param {number} width The chart width. 176 * @param {number} height The chart height. 177 * @return {string} Returns wrapped VML markup. 178 * @private 179 */ 180 function wrapVmlContent_(content, width, height) { 181 return '<v:group coordorigin="0 0" ' + 182 'coordsize="' + width + ' ' + height + '" ' + 183 'style="position:absolute;left:0;top:0;' + 184 'width:' + width + 'px;height:' + height + 'px">' + 185 content + '</v:group>'; 186 } 187 188 /** 189 * Initializes default behaviors. 190 * @private 191 */ 192 function init_() { 193 194 if (!charts.IS_SVG_SUPPORTED) { 195 try { 196 dom.document['namespaces']['add']( 197 'v', 'urn:schemas-microsoft-com:vml', '#default#VML'); 198 } catch (e) { 199 //window.console && console.log(['vml:namespaces.add', e.message || e]); 200 } 201 202 try { 203 /** @type {Object} */ var sheet = dom.document['createStyleSheet'](); 204 sheet['addRule']('v\\:group', 205 'behavior:url(#default#VML);antialias:true;' + 206 'display:inline-block'); 207 } catch (e) { 208 //window.console && console.log(['vml:sheet.addRule', e.message || e]); 209 } 210 } 211 } 212 213 /** 214 * The reference to current class instance. Used in private methods. 215 * @type {!charts.BaseChart} 216 * @private 217 */ 218 var self_ = this; 219 220 init_(); 221 }; 222 223 224 /** 225 * List of default colors. 226 * @type {!Array.<string>} 227 * @static 228 */ 229 charts.BaseChart.DEFAULT_COLORS = [ 230 '#3366BB', '#DD3311', '#FF9911', '#119911', '#991199', 231 '#0099CC', '#DD4488', '#66AA33', '#BB2222', '#336699', 232 '#9955AA', '#11AA99', '#AABB11', '#6633DD', '#EE7700', 233 '#880000', '#661166', '#339966', '#5577AA', '#3333AA', 234 '#BB7722', '#11DD22', '#BB1188', '#FF3399', '#995533', 235 '#AACC11', '#227788', '#668811', '#BBAA11', '#005522', 236 '#773311', '#4EDB05', '#377D18', '#AD9E88', '#4C49E3', 237 '#86D0DD', '#5613EA', '#29F847', '#828295', '#B7F439', 238 '#224256', '#490A7F', '#622A17', '#E188A1', '#F65A2D', 239 '#87F586', '#DF56E4', '#F3E815', '#C528D6', '#32BDC0', 240 '#91F51C', '#A75590', '#556F7C', '#520036', '#64B6AA', 241 '#825B4A', '#63B75A', '#DC8BF7', '#811D02', '#FB1D45', 242 '#76856A', '#F240BB', '#D53C9B', '#67AEC8', '#01786A', 243 '#A08A65', '#715E3F', '#92B88A', '#3A5D6D', '#B8D9D9', 244 '#622C1B', '#1F566F', '#F221EE', '#04808D', '#7A787A', 245 '#F48A8A', '#A60FFA', '#5FDF71', '#F4D11E', '#EDA971', 246 '#3F0AF2', '#E84203', '#2344FA', '#98CFB5', '#E0F068', 247 '#83D7E3', '#1500EA', '#99C760', '#21E636', '#241BB8', 248 '#C44FF5', '#3499BF', '#CFC58F', '#91A739', '#7222B0']; 249