X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/docs/source/Gauge2.html diff --git a/docs/source/Gauge2.html b/docs/source/Gauge2.html new file mode 100644 index 00000000..a632fc5c --- /dev/null +++ b/docs/source/Gauge2.html @@ -0,0 +1,455 @@ +
\ No newline at end of file/** + * @class Ext.chart.series.Gauge + * @extends Ext.chart.series.Series + * + * Creates a Gauge Chart. Gauge Charts are used to show progress in a certain variable. There are two ways of using the Gauge chart. + * One is setting a store element into the Gauge and selecting the field to be used from that store. Another one is instanciating the + * visualization and using the `setValue` method to adjust the value you want. + * + * A chart/series configuration for the Gauge visualization could look like this: + * + * { + * xtype: 'chart', + * store: store, + * axes: [{ + * type: 'gauge', + * position: 'gauge', + * minimum: 0, + * maximum: 100, + * steps: 10, + * margin: -10 + * }], + * series: [{ + * type: 'gauge', + * field: 'data1', + * donut: false, + * colorSet: ['#F49D10', '#ddd'] + * }] + * } + * + * In this configuration we create a special Gauge axis to be used with the gauge visualization (describing half-circle markers), and also we're + * setting a maximum, minimum and steps configuration options into the axis. The Gauge series configuration contains the store field to be bound to + * the visual display and the color set to be used with the visualization. + * + * @xtype gauge + */ +Ext.define('Ext.chart.series.Gauge', { + + /* Begin Definitions */ + + extend: 'Ext.chart.series.Series', + + /* End Definitions */ + + type: "gauge", + alias: 'series.gauge', + + rad: Math.PI / 180, + + /** + * @cfg {Number} highlightDuration + * The duration for the pie slice highlight effect. + */ + highlightDuration: 150, + + /** + * @cfg {String} angleField + * The store record field name to be used for the pie angles. + * The values bound to this field name must be positive real numbers. + * This parameter is required. + */ + angleField: false, + + /** + * @cfg {Boolean} needle + * Use the Gauge Series as an area series or add a needle to it. Default's false. + */ + needle: false, + + /** + * @cfg {Boolean|Number} donut + * Use the entire disk or just a fraction of it for the gauge. Default's false. + */ + donut: false, + + /** + * @cfg {Boolean} showInLegend + * Whether to add the pie chart elements as legend items. Default's false. + */ + showInLegend: false, + + /** + * @cfg {Object} style + * An object containing styles for overriding series styles from Theming. + */ + style: {}, + + constructor: function(config) { + this.callParent(arguments); + var me = this, + chart = me.chart, + surface = chart.surface, + store = chart.store, + shadow = chart.shadow, i, l, cfg; + Ext.apply(me, config, { + shadowAttributes: [{ + "stroke-width": 6, + "stroke-opacity": 1, + stroke: 'rgb(200, 200, 200)', + translate: { + x: 1.2, + y: 2 + } + }, + { + "stroke-width": 4, + "stroke-opacity": 1, + stroke: 'rgb(150, 150, 150)', + translate: { + x: 0.9, + y: 1.5 + } + }, + { + "stroke-width": 2, + "stroke-opacity": 1, + stroke: 'rgb(100, 100, 100)', + translate: { + x: 0.6, + y: 1 + } + }] + }); + me.group = surface.getGroup(me.seriesId); + if (shadow) { + for (i = 0, l = me.shadowAttributes.length; i < l; i++) { + me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i)); + } + } + surface.customAttributes.segment = function(opt) { + return me.getSegment(opt); + }; + }, + + //@private updates some onbefore render parameters. + initialize: function() { + var me = this, + store = me.chart.substore || me.chart.store; + //Add yFields to be used in Legend.js + me.yField = []; + if (me.label.field) { + store.each(function(rec) { + me.yField.push(rec.get(me.label.field)); + }); + } + }, + + // @private returns an object with properties for a Slice + getSegment: function(opt) { + var me = this, + rad = me.rad, + cos = Math.cos, + sin = Math.sin, + abs = Math.abs, + x = me.centerX, + y = me.centerY, + x1 = 0, x2 = 0, x3 = 0, x4 = 0, + y1 = 0, y2 = 0, y3 = 0, y4 = 0, + delta = 1e-2, + r = opt.endRho - opt.startRho, + startAngle = opt.startAngle, + endAngle = opt.endAngle, + midAngle = (startAngle + endAngle) / 2 * rad, + margin = opt.margin || 0, + flag = abs(endAngle - startAngle) > 180, + a1 = Math.min(startAngle, endAngle) * rad, + a2 = Math.max(startAngle, endAngle) * rad, + singleSlice = false; + + x += margin * cos(midAngle); + y += margin * sin(midAngle); + + x1 = x + opt.startRho * cos(a1); + y1 = y + opt.startRho * sin(a1); + + x2 = x + opt.endRho * cos(a1); + y2 = y + opt.endRho * sin(a1); + + x3 = x + opt.startRho * cos(a2); + y3 = y + opt.startRho * sin(a2); + + x4 = x + opt.endRho * cos(a2); + y4 = y + opt.endRho * sin(a2); + + if (abs(x1 - x3) <= delta && abs(y1 - y3) <= delta) { + singleSlice = true; + } + //Solves mysterious clipping bug with IE + if (singleSlice) { + return { + path: [ + ["M", x1, y1], + ["L", x2, y2], + ["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4], + ["Z"]] + }; + } else { + return { + path: [ + ["M", x1, y1], + ["L", x2, y2], + ["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4], + ["L", x3, y3], + ["A", opt.startRho, opt.startRho, 0, +flag, 0, x1, y1], + ["Z"]] + }; + } + }, + + // @private utility function to calculate the middle point of a pie slice. + calcMiddle: function(item) { + var me = this, + rad = me.rad, + slice = item.slice, + x = me.centerX, + y = me.centerY, + startAngle = slice.startAngle, + endAngle = slice.endAngle, + radius = Math.max(('rho' in slice) ? slice.rho: me.radius, me.label.minMargin), + donut = +me.donut, + a1 = Math.min(startAngle, endAngle) * rad, + a2 = Math.max(startAngle, endAngle) * rad, + midAngle = -(a1 + (a2 - a1) / 2), + xm = x + (item.endRho + item.startRho) / 2 * Math.cos(midAngle), + ym = y - (item.endRho + item.startRho) / 2 * Math.sin(midAngle); + + item.middle = { + x: xm, + y: ym + }; + }, + + /** + * Draws the series for the current chart. + */ + drawSeries: function() { + var me = this, + chart = me.chart, + store = chart.substore || chart.store, + group = me.group, + animate = me.chart.animate, + axis = me.chart.axes.get(0), + minimum = axis && axis.minimum || me.minimum || 0, + maximum = axis && axis.maximum || me.maximum || 0, + field = me.angleField || me.field || me.xField, + surface = chart.surface, + chartBBox = chart.chartBBox, + rad = me.rad, + donut = +me.donut, + values = {}, + items = [], + seriesStyle = me.seriesStyle, + seriesLabelStyle = me.seriesLabelStyle, + colorArrayStyle = me.colorArrayStyle, + colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0, + gutterX = chart.maxGutter[0], + gutterY = chart.maxGutter[1], + cos = Math.cos, + sin = Math.sin, + rendererAttributes, centerX, centerY, slice, slices, sprite, value, + item, ln, record, i, j, startAngle, endAngle, middleAngle, sliceLength, path, + p, spriteOptions, bbox, splitAngle, sliceA, sliceB; + + Ext.apply(seriesStyle, me.style || {}); + + me.setBBox(); + bbox = me.bbox; + + //override theme colors + if (me.colorSet) { + colorArrayStyle = me.colorSet; + colorArrayLength = colorArrayStyle.length; + } + + //if not store or store is empty then there's nothing to draw + if (!store || !store.getCount()) { + return; + } + + centerX = me.centerX = chartBBox.x + (chartBBox.width / 2); + centerY = me.centerY = chartBBox.y + chartBBox.height; + me.radius = Math.min(centerX - chartBBox.x, centerY - chartBBox.y); + me.slices = slices = []; + me.items = items = []; + + if (!me.value) { + record = store.getAt(0); + me.value = record.get(field); + } + + value = me.value; + if (me.needle) { + sliceA = { + series: me, + value: value, + startAngle: -180, + endAngle: 0, + rho: me.radius + }; + splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum)); + slices.push(sliceA); + } else { + splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum)); + sliceA = { + series: me, + value: value, + startAngle: -180, + endAngle: splitAngle, + rho: me.radius + }; + sliceB = { + series: me, + value: me.maximum - value, + startAngle: splitAngle, + endAngle: 0, + rho: me.radius + }; + slices.push(sliceA, sliceB); + } + + //do pie slices after. + for (i = 0, ln = slices.length; i < ln; i++) { + slice = slices[i]; + sprite = group.getAt(i); + //set pie slice properties + rendererAttributes = Ext.apply({ + segment: { + startAngle: slice.startAngle, + endAngle: slice.endAngle, + margin: 0, + rho: slice.rho, + startRho: slice.rho * +donut / 100, + endRho: slice.rho + } + }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {})); + + item = Ext.apply({}, + rendererAttributes.segment, { + slice: slice, + series: me, + storeItem: record, + index: i + }); + items[i] = item; + // Create a new sprite if needed (no height) + if (!sprite) { + spriteOptions = Ext.apply({ + type: "path", + group: group + }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {})); + sprite = surface.add(Ext.apply(spriteOptions, rendererAttributes)); + } + slice.sprite = slice.sprite || []; + item.sprite = sprite; + slice.sprite.push(sprite); + if (animate) { + rendererAttributes = me.renderer(sprite, record, rendererAttributes, i, store); + sprite._to = rendererAttributes; + me.onAnimate(sprite, { + to: rendererAttributes + }); + } else { + rendererAttributes = me.renderer(sprite, record, Ext.apply(rendererAttributes, { + hidden: false + }), i, store); + sprite.setAttributes(rendererAttributes, true); + } + } + + if (me.needle) { + splitAngle = splitAngle * Math.PI / 180; + + if (!me.needleSprite) { + me.needleSprite = me.chart.surface.add({ + type: 'path', + path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle), + centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)), + 'L', centerX + me.radius * cos(splitAngle), + centerY + -Math.abs(me.radius * sin(splitAngle))], + 'stroke-width': 4, + 'stroke': '#222' + }); + } else { + if (animate) { + me.onAnimate(me.needleSprite, { + to: { + path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle), + centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)), + 'L', centerX + me.radius * cos(splitAngle), + centerY + -Math.abs(me.radius * sin(splitAngle))] + } + }); + } else { + me.needleSprite.setAttributes({ + type: 'path', + path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle), + centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)), + 'L', centerX + me.radius * cos(splitAngle), + centerY + -Math.abs(me.radius * sin(splitAngle))] + }); + } + } + me.needleSprite.setAttributes({ + hidden: false + }, true); + } + + delete me.value; + }, + + /** + * Sets the Gauge chart to the current specified value. + */ + setValue: function (value) { + this.value = value; + this.drawSeries(); + }, + + // @private callback for when creating a label sprite. + onCreateLabel: function(storeItem, item, i, display) {}, + + // @private callback for when placing a label sprite. + onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {}, + + // @private callback for when placing a callout. + onPlaceCallout: function() {}, + + // @private handles sprite animation for the series. + onAnimate: function(sprite, attr) { + sprite.show(); + return this.callParent(arguments); + }, + + isItemInPoint: function(x, y, item, i) { + return false; + }, + + // @private shows all elements in the series. + showAll: function() { + if (!isNaN(this._index)) { + this.__excludes[this._index] = false; + this.drawSeries(); + } + }, + + /** + * Returns the color of the series (to be displayed as color for the series legend item). + * @param item {Object} Info about the item; same format as returned by #getItemForPoint + */ + getLegendColor: function(index) { + var me = this; + return me.colorArrayStyle[index % me.colorArrayStyle.length]; + } +}); + +