/** * @class Ext.chart.series.Cartesian * * Common base class for series implementations which plot values using x/y coordinates. */ Ext.define('Ext.chart.series.Cartesian', { /* Begin Definitions */ extend: 'Ext.chart.series.Series', alternateClassName: ['Ext.chart.CartesianSeries', 'Ext.chart.CartesianChart'], /* End Definitions */ /** * The field used to access the x axis value from the items from the data * source. * * @cfg xField * @type String */ xField: null, /** * The field used to access the y-axis value from the items from the data * source. * * @cfg yField * @type String */ yField: null, /** * @cfg {String/String[]} axis * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'. * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a * relative scale will be used. For example, if you're using a Scatter or Line series and you'd like to have the * values in the chart relative to the bottom and left axes then `axis` should be `['left', 'bottom']`. */ axis: 'left', getLegendLabels: function() { var me = this, labels = [], fields, i, ln, combinations = me.combinations, title, combo, label0, label1; fields = [].concat(me.yField); for (i = 0, ln = fields.length; i < ln; i++) { title = me.title; // Use the 'title' config if present, otherwise use the raw yField name labels.push((Ext.isArray(title) ? title[i] : title) || fields[i]); } // Handle yFields combined via legend drag-drop // TODO need to check to see if this is supported in extjs 4 branch if (combinations) { combinations = Ext.Array.from(combinations); for (i = 0, ln = combinations.length; i < ln; i++) { combo = combinations[i]; label0 = labels[combo[0]]; label1 = labels[combo[1]]; labels[combo[1]] = label0 + ' & ' + label1; labels.splice(combo[0], 1); } } return labels; }, /** * @protected Iterates over a given record's values for each of this series's yFields, * executing a given function for each value. Any yFields that have been combined * via legend drag-drop will be treated as a single value. * @param {Ext.data.Model} record * @param {Function} fn * @param {Object} scope */ eachYValue: function(record, fn, scope) { var me = this, yValueAccessors = me.getYValueAccessors(), i, ln, accessor; for (i = 0, ln = yValueAccessors.length; i < ln; i++) { accessor = yValueAccessors[i]; fn.call(scope, accessor(record), i); } }, /** * @protected Returns the number of yField values, taking into account fields combined * via legend drag-drop. * @return {Number} */ getYValueCount: function() { return this.getYValueAccessors().length; }, combine: function(index1, index2) { var me = this, accessors = me.getYValueAccessors(), accessor1 = accessors[index1], accessor2 = accessors[index2]; // Combine the yValue accessors for the two indexes into a single accessor that returns their sum accessors[index2] = function(record) { return accessor1(record) + accessor2(record); }; accessors.splice(index1, 1); me.callParent([index1, index2]); }, clearCombinations: function() { // Clear combined accessors, they'll get regenerated on next call to getYValueAccessors delete this.yValueAccessors; this.callParent(); }, /** * @protected Returns an array of functions, each of which returns the value of the yField * corresponding to function's index in the array, for a given record (each function takes the * record as its only argument.) If yFields have been combined by the user via legend drag-drop, * this list of accessors will be kept in sync with those combinations. * @return {Array} array of accessor functions */ getYValueAccessors: function() { var me = this, accessors = me.yValueAccessors, yFields, yField, i, ln; if (!accessors) { accessors = me.yValueAccessors = []; yFields = [].concat(me.yField); for (i = 0, ln = yFields.length; i < ln; i++) { yField = yFields[i]; accessors.push(function(record) { return record.get(yField); }); } } return accessors; }, /** * Calculate the min and max values for this series's xField. * @return {Array} [min, max] */ getMinMaxXValues: function() { var me = this, chart = me.chart, store = chart.getChartStore(), data = store.data.items, i, ln, record, min, max, xField = me.xField, xValue; if (me.getRecordCount() > 0) { min = Infinity; max = -min; for (i = 0, ln = data.length; i < ln; i++) { record = data[i]; xValue = record.get(xField); if (xValue > max) { max = xValue; } if (xValue < min) { min = xValue; } } } else { min = max = 0; } return [min, max]; }, /** * Calculate the min and max values for this series's yField(s). Takes into account yField * combinations, exclusions, and stacking. * @return {Array} [min, max] */ getMinMaxYValues: function() { var me = this, chart = me.chart, store = chart.getChartStore(), data = store.data.items, i, ln, record, stacked = me.stacked, min, max, positiveTotal, negativeTotal; function eachYValueStacked(yValue, i) { if (!me.isExcluded(i)) { if (yValue < 0) { negativeTotal += yValue; } else { positiveTotal += yValue; } } } function eachYValue(yValue, i) { if (!me.isExcluded(i)) { if (yValue > max) { max = yValue; } if (yValue < min) { min = yValue; } } } if (me.getRecordCount() > 0) { min = Infinity; max = -min; for (i = 0, ln = data.length; i < ln; i++) { record = data[i]; if (stacked) { positiveTotal = 0; negativeTotal = 0; me.eachYValue(record, eachYValueStacked); if (positiveTotal > max) { max = positiveTotal; } if (negativeTotal < min) { min = negativeTotal; } } else { me.eachYValue(record, eachYValue); } } } else { min = max = 0; } return [min, max]; }, getAxesForXAndYFields: function() { var me = this, axes = me.chart.axes, axis = [].concat(me.axis), yFields = {}, yFieldList = [].concat(me.yField), xFields = {}, xFieldList = [].concat(me.xField), fields, xAxis, yAxis, i, ln, flipXY; flipXY = me.type === 'bar' && me.column === false; if(flipXY) { fields = yFieldList; yFieldList = xFieldList; xFieldList = fields; } if (Ext.Array.indexOf(axis, 'top') > -1) { xAxis = 'top'; } else if (Ext.Array.indexOf(axis, 'bottom') > -1) { xAxis = 'bottom'; } else { if (axes.get('top') && axes.get('bottom')) { for (i = 0, ln = xFieldList.length; i < ln; i++) { xFields[xFieldList[i]] = true; } fields = [].concat(axes.get('bottom').fields); for (i = 0, ln = fields.length; i < ln; i++) { if (xFields[fields[i]]) { xAxis = 'bottom'; break } } fields = [].concat(axes.get('top').fields); for (i = 0, ln = fields.length; i < ln; i++) { if (xFields[fields[i]]) { xAxis = 'top'; break } } } else if (axes.get('top')) { xAxis = 'top'; } else if (axes.get('bottom')) { xAxis = 'bottom'; } } if (Ext.Array.indexOf(axis, 'left') > -1) { yAxis = 'left'; } else if (Ext.Array.indexOf(axis, 'right') > -1) { yAxis = 'right'; } else { if (axes.get('left') && axes.get('right')) { for (i = 0, ln = yFieldList.length; i < ln; i++) { yFields[yFieldList[i]] = true; } fields = [].concat(axes.get('right').fields); for (i = 0, ln = fields.length; i < ln; i++) { if (yFields[fields[i]]) { break } } fields = [].concat(axes.get('left').fields); for (i = 0, ln = fields.length; i < ln; i++) { if (yFields[fields[i]]) { yAxis = 'left'; break } } } else if (axes.get('left')) { yAxis = 'left'; } else if (axes.get('right')) { yAxis = 'right'; } } return flipXY ? { xAxis: yAxis, yAxis: xAxis }: { xAxis: xAxis, yAxis: yAxis }; } });