(JQuery)通过改写flot的pie插件实现一个speedo meter chart的flot插件

由于项目中需要使用到speedo meter chart,但是又不能使用flash(因为要支持iphone),而speedo的js插件网上貌似很难找到,找到了一个但是却不是很满意,因为没办法灵活的定义UI(如果有需要链接在这里http://plugins.jquery.com/project/speedometer),因为实现起来不是很复杂,而且刚好的flot插件中也有一个pie的plugin,想了一下通过修改这个plugin来实现的话就可以了,下面给出这个代码的api定义:

 

// 这里的API是flot相关的,具体还需参见flot的API定义

series: {

meter:{ // 定义了一个meter object,所有的参数定义都在这里 show: true,  // 是否显示该chart label: { // 是否显示各个段的百分比及名称 show: false },

radius: 1,  // 圆的半径定义,数值是0-1,是一个比例值,基数是整个chart的宽度的一半,默认是1

innerRadius: 0.5,  // 内圆的半径定义,也就是空白部分的范围,通过它来调整遮罩范围,也是一个比例值,同上,默认是0.5

currentValue: 0, // 当前此chart对应指针指定的数值,如果没有默认是0

pointerLength: 0.75, // 指针长度,是一个比例值,基数是radius的长度,默认是0.75

maxScale: 100, // 当前chart反应的最大值标量,如果没有输入默认显示100%,接受一个浮点型的数

title: 'the speedo chart' // chart的title,默认是speedo chart }

 

}

 

你还可以为chart所对应的div做css定义,这样的话就可以有不同的边框和背景了,可以根据你的网站样式作出不同的调整,而meter的颜色定义则还是由flot的定义给出,这里不做修改

 

下面贴出整个插件的源码:

 

 

(function ($) 
{
		function init(plot) // this is the "body" of the plugin
        {
                var canvas = null;
                var target = null;
                var maxRadius = null;
				var currentRadius = null;
                var centerLeft = null;
                var centerTop = null;
                var total = 0;
                var redraw = true;
                var redrawAttempts = 10;
                var shrink = 0.95;
                var legendWidth = 0;
                var processed = false;
                var raw = false;
                
                // interactive variables        
                var highlights = [];    
        
                // add hook to determine if meter plugin in enabled, and then perform necessary operations
                plot.hooks.processOptions.push(checkPieEnabled);
                plot.hooks.bindEvents.push(bindEvents); 

                // check to see if the meter plugin is enabled
                function checkPieEnabled(plot, options)
                {
                        if (options.series.meter.show)
                        {
                                //disable grid
                                options.grid.show = false;
                                
                                // set labels.show
                                if (options.series.meter.label.show=='auto')
                                        if (options.legend.show)
                                                options.series.meter.label.show = false;
                                        else
                                                options.series.meter.label.show = true;
                                
                                // set radius
                                if (options.series.meter.radius=='auto')
                                        if (options.series.meter.label.show)
                                                options.series.meter.radius = 3/4;
                                        else
                                                options.series.meter.radius = 1;
								

								if(!options.series.meter.innerRadius) 
									options.series.meter.innerRadius = options.series.meter.radius/2;

								if (!options.series.meter.title) 
									options.series.meter.title = "Meter Chart";

								if(!options.series.meter.currentValue)
									options.series.meter.currentValue = 0;
                                                
								if(!options.series.meter.pointerLength)
									options.series.meter.pointerLength = options.series.meter.radius*3/4;

                                // ensure sane tilt
                                if (options.series.meter.tilt>1)
                                        options.series.meter.tilt=1;
                                if (options.series.meter.tilt<0)
                                        options.series.meter.tilt=0;							

								if (!options.series.meter.maxScale)
                                        options.series.meter.maxScale="100%"; // treate as percentage value

								options.series.meter.startAngle = 1;
								
                                // add processData hook to do transformations on the data
                                plot.hooks.processDatapoints.push(processDatapoints);
                                plot.hooks.drawOverlay.push(drawOverlay);       
                                
                                // add draw hook
                                plot.hooks.draw.push(draw);
                        }
                }
        
                // bind hoverable events
                function bindEvents(plot, eventHolder)          
                {               
                        var options = plot.getOptions();
                        
                        if (options.series.meter.show && options.grid.hoverable)
                                eventHolder.unbind('mousemove').mousemove(onMouseMove);
                                
                        if (options.series.meter.show && options.grid.clickable)
                                eventHolder.unbind('click').click(onClick);
                }       
                

                // debugging function that prints out an object
                function alertObject(obj)
                {
                        var msg = '';
                        function traverse(obj, depth)
                        {
                                if (!depth)
                                        depth = 0;
                                for (var i = 0; i < obj.length; ++i)
                                {
                                        for (var j=0; j<depth; j++)
                                                msg += '\t';
                                
                                        if( typeof obj[i] == "object")
                                        {       // its an object
                                                msg += ''+i+':\n';
                                                traverse(obj[i], depth+1);
                                        }
                                        else
                                        {       // its a value
                                                msg += ''+i+': '+obj[i]+'\n';
                                        }
                                }
                        }
                        traverse(obj);
                        alert(msg);
                }
                
                function calcTotal(data)
                {
                        for (var i = 0; i < data.length; ++i)
                        {
                                var item = parseFloat(data[i].data[0][1]);
                                if (item)
                                        total += item;
                        }
                }       
                
                function processDatapoints(plot, series, data, datapoints) 
                {       
                        if (!processed)
                        {
                                processed = true;
                        
                                canvas = plot.getCanvas();								
                                target = $(canvas).parent();								
                                options = plot.getOptions();
                        
                                plot.setData(combine(plot.getData()));
                        }
                }
                
                function setupPie()
                {
                        legendWidth = target.children().filter('.legend').children().width();
                
                        // calculate maximum radius and center point
                        maxRadius =  canvas.width/2;
                        centerTop = (canvas.height)+options.series.meter.offset.top;
                        centerLeft = (canvas.width/2);
                        
                        if (options.series.meter.offset.left=='auto')
                                if (options.legend.position.match('w'))
                                        centerLeft += legendWidth/2;
                                else
                                        centerLeft -= legendWidth/2;
                        else
                                centerLeft += options.series.meter.offset.left;
                                        
                        if (centerLeft<maxRadius)
                                centerLeft = maxRadius;
                        else if (centerLeft>canvas.width-maxRadius)
                                centerLeft = canvas.width-maxRadius;
                }
                
                function fixData(data)
                {
                        for (var i = 0; i < data.length; ++i)
                        {
                                if (typeof(data[i].data)=='number')
                                        data[i].data = [[1,data[i].data]];
                                else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
                                {
                                        if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
                                                data[i].label = data[i].data.label; // fix weirdness coming from flot
                                        data[i].data = [[1,0]];
                                        
                                }
                        }
                        return data;
                }
                
                function combine(data)
                {
                        data = fixData(data);
                        calcTotal(data);
                        var combined = 0;
                        var numCombined = 0;
                        var color = options.series.meter.combine.color;
                        
                        var newdata = [];
                        for (var i = 0; i < data.length; ++i)
                        {
                                // make sure its a number
                                data[i].data[0][1] = parseFloat(data[i].data[0][1]);
                                if (!data[i].data[0][1])
                                        data[i].data[0][1] = 0;
                                        
                                if (data[i].data[0][1]/total<=options.series.meter.combine.threshold)
                                {
                                        combined += data[i].data[0][1];
                                        numCombined++;
                                        if (!color)
                                                color = data[i].color;
                                }                               
                                else
                                {
                                        newdata.push({
                                                data: [[1,data[i].data[0][1]]], 
                                                color: data[i].color, 
                                                label: data[i].label,
                                                angle: (data[i].data[0][1]*(Math.PI))/total,
                                                percent: (data[i].data[0][1]/total*100)
                                        });
                                }
                        }
                        if (numCombined>0)
                                newdata.push({
                                        data: [[1,combined]], 
                                        color: color, 
                                        label: options.series.meter.combine.label,
                                        angle: (combined*(Math.PI))/total,
                                        percent: (combined/total*100)
                                });
                        return newdata;
                }               
                
                function draw(plot, newCtx)
                {
                        if (!target) return; // if no series were passed
                        ctx = newCtx;
                
                        setupPie();
                        var slices = plot.getData();
                
                        var attempts = 0;
                        while (redraw && attempts<redrawAttempts)
                        {
                                redraw = false;
                                if (attempts>0)
                                        maxRadius *= shrink;
                                attempts += 1;
                                clear();
                                if (options.series.meter.tilt<=0.8)
                                        drawShadow();
                                drawPie();
                        }
                        if (attempts >= redrawAttempts) {
                                clear();
                                target.prepend('<div class="error">Could not draw meter with labels contained inside canvas</div>');
                        }
                        
                        if ( plot.setSeries && plot.insertLegend )
                        {
                                plot.setSeries(slices);
                                plot.insertLegend();
                        }
                        
                        // we're actually done at this point, just defining internal functions at this point
                        
                        function clear()
                        {
                                ctx.clearRect(0,0,canvas.width,canvas.height);
                                target.children().filter('.pieLabel, .pieLabelBackground').remove();
                        }
                        
                        function drawShadow()
                        {
                                var shadowLeft = 5;
                                var shadowTop = 15;
                                var edge = 10;
                                var alpha = 0.02;
                        
                                // set radius
                                if (options.series.meter.radius>1)
                                        var radius = options.series.meter.radius;
                                else
                                        var radius = maxRadius * options.series.meter.radius;
                                        
                                if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.meter.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
                                        return; // shadow would be outside canvas, so don't draw it
                        
                                ctx.save();
                                ctx.translate(shadowLeft,shadowTop);
                                ctx.globalAlpha = alpha;
                                ctx.fillStyle = '#000';

                                // center and rotate to starting position
                                ctx.translate(centerLeft,centerTop);
                                ctx.scale(1, options.series.meter.tilt);
                                
                                //radius -= edge;
                                for (var i=1; i<=edge; i++)
                                {
                                        ctx.beginPath();
                                        ctx.arc(0,0,radius,0,Math.PI,false);
                                        ctx.fill();
                                        radius -= i;
                                }       
                                
                                ctx.restore();
                        }
                        
                        function drawPie()
                        {
                                startAngle = Math.PI*options.series.meter.startAngle;
                                
                                // set radius
                                if (options.series.meter.radius>1)
                                        var radius = options.series.meter.radius;
                                else
                                        var radius = maxRadius * options.series.meter.radius;
                                
                                // center and rotate to starting position
                                ctx.save();
                                ctx.translate(centerLeft,centerTop);
                                ctx.scale(1, options.series.meter.tilt);
                                //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
                                
                                // draw slices
                                ctx.save();
                                var currentAngle = startAngle;
                                for (var i = 0; i < slices.length; ++i)
                                {
                                        slices[i].startAngle = currentAngle;
                                        drawSlice(slices[i].angle, slices[i].color, true);
                                }
                                ctx.restore();
                                
                                // draw slice outlines
                                ctx.save();
                                ctx.lineWidth = options.series.meter.stroke.width;
                                currentAngle = startAngle;
                                for (var i = 0; i < slices.length; ++i)
                                        drawSlice(slices[i].angle, options.series.meter.stroke.color, false);
                                ctx.restore();
                                        
                                // draw donut hole
                                drawDonutHole(ctx);
                                
                                // draw labels
                                if (options.series.meter.label.show)
                                        drawLabels();
								printTitle();
                                
                                // restore to original state
                                ctx.restore();

								// print scale
								printScaleText();

								// draw pointer
								drawPointer();

								// print current scale 
								printCurentScaleValue();
                                
                                function drawSlice(angle, color, fill)
                                {       
                                        if (angle<=0)
                                                return;
                                
                                        if (fill)
                                                ctx.fillStyle = color;
                                        else
                                        {
                                                ctx.strokeStyle = color;
                                                ctx.lineJoin = 'round';
                                        }
                                                
                                        ctx.beginPath();
                                        if (Math.abs(angle - Math.PI) > 0.000000001)
                                                ctx.moveTo(0,0); // Center of the meter
                                        else if ($.browser.msie)
                                                angle -= 0.0001;
                                        //ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
                                        ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
                                        ctx.closePath();
                                        //ctx.rotate(angle); // This doesn't work properly in Opera
                                        currentAngle += angle;
                                        
                                        if (fill)
                                                ctx.fill();
                                        else
                                                ctx.stroke();
                                }
                                
                                function drawLabels()
                                {
                                        var currentAngle = startAngle;
                                        
                                        // set radius
                                        if (options.series.meter.label.radius>1)
                                                var radius = options.series.meter.label.radius;
                                        else
                                                var radius = maxRadius * options.series.meter.label.radius;
                                  
                                        for (var i = 0; i < slices.length; ++i)
                                        {
                                                if (slices[i].percent >= options.series.meter.label.threshold*100)
                                                        drawLabel(slices[i], currentAngle, i);
                                                currentAngle += slices[i].angle;
                                        }
                                        
                                        function drawLabel(slice, startAngle, index)
                                        {
                                                if (slice.data[0][1]==0)
                                                        return;
                                                        
                                                // format label text
                                                var lf = options.legend.labelFormatter, text, plf = options.series.meter.label.formatter;
                                                if (lf)
                                                        text = lf(slice.label, slice);
                                                else
                                                        text = slice.label;
                                                if (plf)
                                                        text = plf(text, slice);
                                                        
                                                var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
                                                var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
                                                var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.meter.tilt;
                                                
                                                var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
                                                target.append(html);
                                                var label = target.children('#pieLabel'+index);
                                                var labelTop = (y - label.height()/2);
                                                var labelLeft = (x - label.width()/2);
                                                label.css('top', labelTop);
                                                label.css('left', labelLeft);
                                                
                                                // check to make sure that the label is not outside the canvas
                                                if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
                                                        redraw = true;
                                                
                                                if (options.series.meter.label.background.opacity != 0) {
                                                        // put in the transparent background separately to avoid blended labels and label boxes
                                                        var c = options.series.meter.label.background.color;
                                                        if (c == null) {
                                                                c = slice.color;
                                                        }
                                                        var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
                                                        $('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.meter.label.background.opacity);
                                                }
                                        } // end individual label function
                                } // end drawLabels function

								function printTitle() {
									var html = "<span class='MeterChart_Title' style='font-size:12px; position:absolute; top:10px;'>"+options.series.meter.title+"</span>";
									$(html).appendTo(target).css("left", (centerLeft-(options.series.meter.title+"").length*getFontSize(html)/4)+"px");
								} // end printTitle function

								function printScaleText() {
									var radius = options.series.meter.radius*maxRadius;
									var innerRadius = options.series.meter.innerRadius*maxRadius;
									// print min scale
									var minScaleHTML = "<span style='font-weight: bold; position:absolute; top:"+centerTop+"px; left: "+(radius-innerRadius)/2*0.9+"px;'>0</span>";
									target.append(minScaleHTML);
									var maxScaleHTML = "<span style='font-weight: bold; position:absolute; top:"+centerTop+"px; left: "+(radius+innerRadius+(radius-innerRadius)/2)*0.95+"px;'>"+options.series.meter.maxScale+"</span>";
									target.append(maxScaleHTML);
								} // end printScale function

								function drawPointer() {
									var value = options.series.meter.currentValue;
									var pointerLength = options.series.meter.pointerLength * maxRadius;
									var maxScale = parseFloat(options.series.meter.maxScale);
									var angle = Math.PI*value/maxScale;
									var pointerWidth = 6;

									var startX = centerLeft - Math.floor(pointerLength*Math.cos(angle))-1;
									var startY = centerTop - Math.floor(pointerLength*Math.sin(angle))-1;
									
									ctx.beginPath();
									ctx.moveTo(startX,startY);
									ctx.lineTo(centerLeft+pointerWidth/2*Math.sin(angle),centerTop-pointerWidth/2*Math.cos(angle));
									ctx.lineTo(centerLeft-pointerWidth/2*Math.sin(angle),centerTop+pointerWidth/2*Math.cos(angle));
									ctx.fill();
								} // end drawPointer function
								
								function printCurentScaleValue() {
									var html = "<div class='MeterChart_Value' style='font-size: 16px; position:absolute; top:"+(centerTop+10)+"px;'>"+options.series.meter.currentValue+"</div>";
									$(html).appendTo(target).css("left", (centerLeft-(options.series.meter.currentValue+"").length*getFontSize(html)/4)+"px");
								} // end printCurentScaleValue function
								
								function getFontSize(html) {
									var fontSize = $(html).css("fontSize");
									if(fontSize.indexOf("px") > -1) {
										fontSize = parseInt(fontSize);
									} else if(fontSize.indexOf("em") > -1) {
										fontSize = Math.floor(parseFloat(fontSize)*16);
									} else if(fontSize.indexOf("pt") > -1) {
										fontSize = Math.floor(parseFloat(fontSize)*4/3);
									} else {
										fontSize = centerLeft;
									}
									return fontSize;
								}
                        } // end drawPie function
                } // end draw function
                
                // Placed here because it needs to be accessed from multiple locations 
                function drawDonutHole(layer)
                {
                        // draw donut hole
                        if(options.series.meter.innerRadius > 0)
                        {
                                // subtract the center
                                layer.save();
                                innerRadius = options.series.meter.innerRadius > 1 ? options.series.meter.innerRadius : maxRadius * options.series.meter.innerRadius;
                                layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
                                layer.beginPath();
                                layer.fillStyle = options.series.meter.stroke.color;
                                layer.arc(0,0,innerRadius,0,Math.PI*2,false);
                                layer.fill();
                                layer.closePath();
                                layer.restore();
                                
                                // add inner stroke
                                layer.save();
                                layer.beginPath();
                                layer.strokeStyle = options.series.meter.stroke.color;
                                layer.arc(0,0,innerRadius,0,Math.PI*2,false);
                                layer.stroke();
                                layer.closePath();
                                layer.restore();
                                // TODO: add extra shadow inside hole (with a mask) if the meter is tilted.
                        }
                }
                
                //-- Additional Interactive related functions --
                
                function isPointInPoly(poly, pt)
                {
                        for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
                                ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
                                && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
                                && (c = !c);
                        return c;
                }
                
                function findNearbySlice(mouseX, mouseY)
                {
                        var slices = plot.getData(),
                                options = plot.getOptions(),
                                radius = options.series.meter.radius > 1 ? options.series.meter.radius : maxRadius * options.series.meter.radius;
                        
                        for (var i = 0; i < slices.length; ++i) 
                        {
                                var s = slices[i];      
                                
                                if(s.meter.show)
                                {
                                        ctx.save();
                                        ctx.beginPath();
                                        ctx.moveTo(0,0); // Center of the meter
                                        //ctx.scale(1, options.series.meter.tilt);        // this actually seems to break everything when here.
                                        ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
                                        ctx.closePath();
                                        x = mouseX-centerLeft;
                                        y = mouseY-centerTop;
                                        if(ctx.isPointInPath)
                                        {
                                                if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
                                                {
                                                        //alert('found slice!');
                                                        ctx.restore();
                                                        return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
                                                }
                                        }
                                        else
                                        {
                                                // excanvas for IE doesn;t support isPointInPath, this is a workaround. 
                                                p1X = (radius * Math.cos(s.startAngle));
                                                p1Y = (radius * Math.sin(s.startAngle));
                                                p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
                                                p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
                                                p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
                                                p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
                                                p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
                                                p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
                                                p5X = (radius * Math.cos(s.startAngle+s.angle));
                                                p5Y = (radius * Math.sin(s.startAngle+s.angle));
                                                arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
                                                arrPoint = [x,y];
                                                // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for meter tilt?
                                                if(isPointInPoly(arrPoly, arrPoint))
                                                {
                                                        ctx.restore();
                                                        return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
                                                }                       
                                        }
                                        ctx.restore();
                                }
                        }
                        
                        return null;
                }

                function onMouseMove(e) 
                {
                        triggerClickHoverEvent('plothover', e);
                }
                
        function onClick(e) 
                {
                        triggerClickHoverEvent('plotclick', e);
        }

                // trigger click or hover event (they send the same parameters so we share their code)
                function triggerClickHoverEvent(eventname, e) 
                {
                        var offset = plot.offset(),
                                canvasX = parseInt(e.pageX - offset.left),
                                canvasY =  parseInt(e.pageY - offset.top),
                                item = findNearbySlice(canvasX, canvasY);
                        
                        if (options.grid.autoHighlight) 
                        {
                                // clear auto-highlights
                                for (var i = 0; i < highlights.length; ++i) 
                                {
                                        var h = highlights[i];
                                        if (h.auto == eventname && !(item && h.series == item.series))
                                                unhighlight(h.series);
                                }
                        }
                        
                        // highlight the slice
                        if (item) 
                            highlight(item.series, eventname);
                                
                        // trigger any hover bind events
                        var pos = { pageX: e.pageX, pageY: e.pageY };
                        target.trigger(eventname, [ pos, item ]);       
                }

                function highlight(s, auto) 
                {
                        if (typeof s == "number")
                                s = series[s];

                        var i = indexOfHighlight(s);
                        if (i == -1) 
                        {
                                highlights.push({ series: s, auto: auto });
                                plot.triggerRedrawOverlay();
                        }
                        else if (!auto)
                                highlights[i].auto = false;
                }

                function unhighlight(s) 
                {
                        if (s == null) 
                        {
                                highlights = [];
                                plot.triggerRedrawOverlay();
                        }
                        
                        if (typeof s == "number")
                                s = series[s];

                        var i = indexOfHighlight(s);
                        if (i != -1) 
                        {
                                highlights.splice(i, 1);
                                plot.triggerRedrawOverlay();
                        }
                }

                function indexOfHighlight(s) 
                {
                        for (var i = 0; i < highlights.length; ++i) 
                        {
                                var h = highlights[i];
                                if (h.series == s)
                                        return i;
                        }
                        return -1;
                }

                function drawOverlay(plot, octx) 
                {
                        //alert(options.series.meter.radius);
                        var options = plot.getOptions();
                        //alert(options.series.meter.radius);
                        
                        var radius = options.series.meter.radius > 1 ? options.series.meter.radius : maxRadius * options.series.meter.radius;

                        octx.save();
                        octx.translate(centerLeft, centerTop);
                        octx.scale(1, options.series.meter.tilt);
                        
                        for (i = 0; i < highlights.length; ++i) 
                                drawHighlight(highlights[i].series);
                        
                        drawDonutHole(octx);

                        octx.restore();

                        function drawHighlight(series) 
                        {
                                if (series.angle < 0) return;
                                
                                //octx.fillStyle = parseColor(options.series.meter.highlight.color).scale(null, null, null, options.series.meter.highlight.opacity).toString();
                                octx.fillStyle = "rgba(255, 255, 255, "+options.series.meter.highlight.opacity+")"; // this is temporary until we have access to parseColor
                                
                                octx.beginPath();
                                if (Math.abs(series.angle - Math.PI) > 0.000000001)
                                        octx.moveTo(0,0); // Center of the meter
                                octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
                                octx.closePath();
                                octx.fill();
                        }
                        
                }       
                
        } // end init (plugin body)
        
        // define meter specific options and their default values
        var options = {
                series: {
                        meter: {
                                show: false,
                                radius: 'auto', // actual radius of the visible meter (based on full calculated radius if <=1, or hard pixel value)
                                innerRadius:0, /* for donut */
                                startAngle: 3/2,
                                tilt: 1,
                                offset: {
                                        top: 0,
                                        left: 'auto'
                                },
                                stroke: {
                                        color: '#FFF',
                                        width: 1
                                },
                                label: {
                                        show: 'auto',
                                        formatter: function(label, slice){
                                                return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
                                        },      // formatter function
                                        radius: 1,      // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
                                        background: {
                                                color: null,
                                                opacity: 0
                                        },
                                        threshold: 0    // percentage at which to hide the label (i.e. the slice is too narrow)
                                },
                                combine: {
                                        threshold: -1,  // percentage at which to combine little slices into one larger slice
                                        color: null,    // color to give the new slice (auto-generated if null)
                                        label: 'Other'  // label to give the new slice
                                },
                                highlight: {
                                        //color: '#FFF',                // will add this functionality once parseColor is available
                                        opacity: 0.5
                                }
                        }
                }
        };
    
        $.plot.plugins.push({
                init: init,
                options: options,
                name: "meter",
                version: "1.0"
        });
})(jQuery);

 

 

使用的前置条件:需要引入flot的jquery组件,然后使用flot的API

 

给出一个简单的结果:

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值