|
/** 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) |
|
}); |
|
|