/** * @class Ext.sparkline.Bullet * * Plots a bullet graph based upon the input {@link #values} array. * * See <a href="http://en.wikipedia.org/wiki/Bullet_graph">Bullet graphs Wikipedia Page</a> * for more information. * * The first value should be the target value. If there is no target value, it should be `null`. * The second value should be the performance value. If there is no performance value, it should be * specified as `null`. * * An example value: * * // Target 10 * // Performance 12 * // Ranges 12,9,7 * [10, 12, 12, 9, 7] * * See {@link Ext.sparkline.Base the base class} for a simple example. */Ext.define('Ext.sparkline.Bullet', { extend: 'Ext.sparkline.Base', alias: 'widget.sparklinebullet', config: { /** * @cfg {String} [targetColor=#f33] The colour of the vertical target marker. */ targetColor: '#f33', /** * @cfg {Number} [targetWidth=3] Width of the target bar in pixels. */ targetWidth: 3, /** * @cfg {String} [performanceColor=#33f] The color of the performance measure * horizontal bar. */ performanceColor: '#33f', /** * @cfg {String[]} [rangeColors] An array of colors to use for each qualitative range * background color. */ rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'], /** * @cfg {Number} [base] Set this to a number to change the base start number. */ base: null }, tipTpl: ['{fieldkey:this.fields} - {value}', { fields: function(v) { if (v === 'r') { return 'Range'; } if (v === 'p') { return 'Performance'; } if (v === 't') { return 'Target'; } } }], // Ensure values is an array of normalized values applyValues: function(newValues) { newValues = Ext.Array.map(Ext.Array.from(newValues), this.normalizeValue); this.disabled = !(newValues && newValues.length); this.updateConfigChange(); return newValues; }, onUpdate: function() { var me = this, values = me.values, min, max, vals, base = me.getBase(); me.callParent(arguments); // target or performance could be null vals = values.slice(); vals[0] = vals[0] === null ? vals[2] : vals[0]; vals[1] = values[1] === null ? vals[2] : vals[1]; min = Math.min.apply(Math, values); max = Math.max.apply(Math, values); if (base == null) { min = min < 0 ? min : 0; } else { min = base; } me.min = min; me.max = max; me.range = max - min; me.shapes = {}; me.valueShapes = {}; me.regiondata = {}; if (!values.length) { me.disabled = true; } }, getRegion: function(x, y) { var shapeid = this.canvas.getShapeAt(x, y); return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined; }, getRegionFields: function(region) { return { fieldkey: region.substr(0, 1), value: this.values[parseInt(region.substr(1), 10)], region: region }; }, renderHighlight: function(region) { var me = this, valueShapes = me.valueShapes, shapes = me.shapes, shapeId = valueShapes[region], shape; delete shapes[shapeId]; switch (region.substr(0, 1)) { case 'r': shape = me.renderRange(parseInt(region.substr(1), 10), true); break; case 'p': shape = me.renderPerformance(true); break; case 't': shape = me.renderTarget(true); break; } valueShapes[region] = shape.id; shapes[shape.id] = region; me.canvas.replaceWithShape(shapeId, shape); }, renderRange: function(region, highlight) { var me = this, rangeval = me.values[region], rangewidth = Math.round(me.getWidth() * ((rangeval - me.min) / me.range)), colors = me.getRangeColors(), color = colors[Math.min(region - 2, colors.length - 1)]; if (highlight) { color = me.calcHighlightColor(color); } return me.canvas.drawRect(0, 0, rangewidth - 1, me.getHeight() - 1, color, color); }, renderPerformance: function(highlight) { var perfval = this.values[1], perfwidth = Math.round(this.getWidth() * ((perfval - this.min) / this.range)), color = this.getPerformanceColor(); if (highlight) { color = this.calcHighlightColor(color); } return this.canvas.drawRect(0, Math.round(this.getHeight() * 0.3), perfwidth - 1, Math.round(this.getHeight() * 0.4) - 1, color, color); }, renderTarget: function(highlight) { var targetval = this.values[0], targetWidth = this.getTargetWidth(), x = Math.round(this.getWidth() * ((targetval - this.min) / this.range) - (targetWidth / 2)), // eslint-disable-line max-len targettop = Math.round(this.getHeight() * 0.10), targetheight = this.getHeight() - (targettop * 2), color = this.getTargetColor(); if (highlight) { color = this.calcHighlightColor(color); } return this.canvas.drawRect(x, targettop, targetWidth - 1, targetheight - 1, color, color); }, renderGraph: function() { var me = this, vlen = me.values.length, canvas = me.canvas, i, shape, shapes = me.shapes || (me.shapes = {}), valueShapes = me.valueShapes || (me.valueShapes = {}); if (!me.callParent()) { return; } for (i = 2; i < vlen; i++) { shape = me.renderRange(i).append(); shapes[shape.id] = 'r' + i; valueShapes['r' + i] = shape.id; } if (me.values[1] !== null) { shape = me.renderPerformance().append(); shapes[shape.id] = 'p1'; valueShapes.p1 = shape.id; } if (me.values[0] !== null) { shape = this.renderTarget().append(); shapes[shape.id] = 't0'; valueShapes.t0 = shape.id; } // If mouse is over, apply the highlight if (me.currentPageXY && me.canvasRegion.contains(me.currentPageXY)) { me.updateDisplay(); } canvas.render(); }, privates: { isValidRegion: function(region, values) { return parseInt(region.substr(1), 10) < values.length; } }});