/** Bubbles **/ Flotr.addType('bubbles', { options: { show: false, // => setting to true will show radar chart, false will hide lineWidth: 2, // => line width in pixels fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill baseRadius: 2 // => ratio of the radar, against the plot size }, draw : function (options) { var context = options.context, shadowSize = options.shadowSize; context.save(); context.lineWidth = options.lineWidth; // Shadows context.fillStyle = 'rgba(0,0,0,0.05)'; context.strokeStyle = 'rgba(0,0,0,0.05)'; this.plot(options, shadowSize / 2); context.strokeStyle = 'rgba(0,0,0,0.1)'; this.plot(options, shadowSize / 4); // Chart context.strokeStyle = options.color; context.fillStyle = options.fillStyle; this.plot(options); context.restore(); }, plot : function (options, offset) { var data = options.data, context = options.context, geometry, i, x, y, z; offset = offset || 0; for (i = 0; i < data.length; ++i){ geometry = this.getGeometry(data[i], options); context.beginPath(); context.arc(geometry.x + offset, geometry.y + offset, geometry.z, 0, 2 * Math.PI, true); context.stroke(); if (options.fill) context.fill(); context.closePath(); } }, getGeometry : function (point, options) { return { x : options.xScale(point[0]), y : options.yScale(point[1]), z : point[2] * options.baseRadius }; }, hit : function (options) { var data = options.data, args = options.args, mouse = args[0], n = args[1], relX = mouse.relX, relY = mouse.relY, distance, geometry, dx, dy; n.best = n.best || Number.MAX_VALUE; for (i = data.length; i--;) { geometry = this.getGeometry(data[i], options); dx = geometry.x - relX; dy = geometry.y - relY; distance = Math.sqrt(dx * dx + dy * dy); if (distance < geometry.z && geometry.z < n.best) { n.x = data[i][0]; n.y = data[i][1]; n.index = i; n.seriesIndex = options.index; n.best = geometry.z; } } }, drawHit : function (options) { var context = options.context, geometry = this.getGeometry(options.data[options.args.index], options); context.save(); context.lineWidth = options.lineWidth; context.fillStyle = options.fillStyle; context.strokeStyle = options.color; context.beginPath(); context.arc(geometry.x, geometry.y, geometry.z, 0, 2 * Math.PI, true); context.fill(); context.stroke(); context.closePath(); context.restore(); }, clearHit : function (options) { var context = options.context, geometry = this.getGeometry(options.data[options.args.index], options), offset = geometry.z + options.lineWidth; context.save(); context.clearRect( geometry.x - offset, geometry.y - offset, 2 * offset, 2 * offset ); context.restore(); } // TODO Add a hit calculation method (like pie) });