/home/techb158/immovalet.ca/bower_components/flot
NameSizeModeActions
examples/-0777rm
.bower.json4490666editdlrm
.gitignore430666editdlrm
.travis.yml380666editdlrm
API.md535720666editdlrm
component.json1140666editdlrm
CONTRIBUTING.md32420666editdlrm
excanvas.js433710666editdlrm
excanvas.min.js193140666editdlrm
FAQ.md32370666editdlrm
flot.jquery.json8360666editdlrm
jquery.colorhelpers.js63310666editdlrm
jquery.flot.canvas.js99440666editdlrm
jquery.flot.categories.js62230666editdlrm
jquery.flot.crosshair.js56010666editdlrm
jquery.flot.errorbars.js129670666editdlrm
jquery.flot.fillbetween.js54830666editdlrm
jquery.flot.image.js76010666editdlrm
jquery.flot.js1247640666editdlrm
jquery.flot.navigate.js145360666editdlrm
jquery.flot.pie.js244510666editdlrm
jquery.flot.resize.js31950666editdlrm
jquery.flot.selection.js135010666editdlrm
jquery.flot.stack.js72780666editdlrm
jquery.flot.symbol.js25760666editdlrm
jquery.flot.threshold.js46220666editdlrm
jquery.flot.time.js121600666editdlrm
jquery.js2755290666editdlrm
LICENSE.txt10910666editdlrm
Makefile2970666editdlrm
NEWS.md383390666editdlrm
package.json1540666editdlrm
PLUGINS.md43400666editdlrm
README.md37820666editdlrm
Edit: /home/techb158/immovalet.ca/bower_components/flot/jquery.flot.pie.js (24451B)
/* Flot plugin for rendering pie charts. Copyright (c) 2007-2013 IOLA and Ole Laursen. Licensed under the MIT license. The plugin assumes that each series has a single data value, and that each value is a positive integer or zero. Negative numbers don't make sense for a pie chart, and have unpredictable results. The values do NOT need to be passed in as percentages; the plugin will calculate the total and per-slice percentages internally. * Created by Brian Medendorp * Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars The plugin supports these options: series: { pie: { show: true/false radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto' innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show) offset: { top: integer value to move the pie up or down left: integer value to move the pie left or right, or 'auto' }, stroke: { color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF') width: integer pixel width of the stroke }, label: { show: true/false, or 'auto' formatter: a user-defined function that modifies the text/style of the label text radius: 0-1 for percentage of fullsize, or a specified pixel length background: { color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000') opacity: 0-1 }, threshold: 0-1 for the percentage value at which to hide labels (if they're too small) }, combine: { threshold: 0-1 for the percentage value at which to combine slices (if they're too small) color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined label: any text value of what the combined slice should be labeled } highlight: { opacity: 0-1 } } } More detail and specific examples can be found in the included HTML file. */ (function($) { // Maximum redraw attempts when fitting labels within the plot var REDRAW_ATTEMPTS = 10; // Factor by which to shrink the pie when fitting labels within the plot var REDRAW_SHRINK = 0.95; function init(plot) { var canvas = null, target = null, options = null, maxRadius = null, centerLeft = null, centerTop = null, processed = false, ctx = null; // interactive variables var highlights = []; // add hook to determine if pie plugin in enabled, and then perform necessary operations plot.hooks.processOptions.push(function(plot, options) { if (options.series.pie.show) { options.grid.show = false; // set labels.show if (options.series.pie.label.show == "auto") { if (options.legend.show) { options.series.pie.label.show = false; } else { options.series.pie.label.show = true; } } // set radius if (options.series.pie.radius == "auto") { if (options.series.pie.label.show) { options.series.pie.radius = 3/4; } else { options.series.pie.radius = 1; } } // ensure sane tilt if (options.series.pie.tilt > 1) { options.series.pie.tilt = 1; } else if (options.series.pie.tilt < 0) { options.series.pie.tilt = 0; } } }); plot.hooks.bindEvents.push(function(plot, eventHolder) { var options = plot.getOptions(); if (options.series.pie.show) { if (options.grid.hoverable) { eventHolder.unbind("mousemove").mousemove(onMouseMove); } if (options.grid.clickable) { eventHolder.unbind("click").click(onClick); } } }); plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) { var options = plot.getOptions(); if (options.series.pie.show) { processDatapoints(plot, series, data, datapoints); } }); plot.hooks.drawOverlay.push(function(plot, octx) { var options = plot.getOptions(); if (options.series.pie.show) { drawOverlay(plot, octx); } }); plot.hooks.draw.push(function(plot, newCtx) { var options = plot.getOptions(); if (options.series.pie.show) { draw(plot, newCtx); } }); function processDatapoints(plot, series, datapoints) { if (!processed) { processed = true; canvas = plot.getCanvas(); target = $(canvas).parent(); options = plot.getOptions(); plot.setData(combine(plot.getData())); } } function combine(data) { var total = 0, combined = 0, numCombined = 0, color = options.series.pie.combine.color, newdata = []; // Fix up the raw data from Flot, ensuring the data is numeric for (var i = 0; i < data.length; ++i) { var value = data[i].data; // If the data is an array, we'll assume that it's a standard // Flot x-y pair, and are concerned only with the second value. // Note how we use the original array, rather than creating a // new one; this is more efficient and preserves any extra data // that the user may have stored in higher indexes. if ($.isArray(value) && value.length == 1) { value = value[0]; } if ($.isArray(value)) { // Equivalent to $.isNumeric() but compatible with jQuery < 1.7 if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) { value[1] = +value[1]; } else { value[1] = 0; } } else if (!isNaN(parseFloat(value)) && isFinite(value)) { value = [1, +value]; } else { value = [1, 0]; } data[i].data = [value]; } // Sum up all the slices, so we can calculate percentages for each for (var i = 0; i < data.length; ++i) { total += data[i].data[0][1]; } // Count the number of slices with percentages below the combine // threshold; if it turns out to be just one, we won't combine. for (var i = 0; i < data.length; ++i) { var value = data[i].data[0][1]; if (value / total <= options.series.pie.combine.threshold) { combined += value; numCombined++; if (!color) { color = data[i].color; } } } for (var i = 0; i < data.length; ++i) { var value = data[i].data[0][1]; if (numCombined < 2 || value / total > options.series.pie.combine.threshold) { newdata.push({ data: [[1, value]], color: data[i].color, label: data[i].label, angle: value * Math.PI * 2 / total, percent: value / (total / 100) }); } } if (numCombined > 1) { newdata.push({ data: [[1, combined]], color: color, label: options.series.pie.combine.label, angle: combined * Math.PI * 2 / total, percent: combined / (total / 100) }); } return newdata; } function draw(plot, newCtx) { if (!target) { return; // if no series were passed } var canvasWidth = plot.getPlaceholder().width(), canvasHeight = plot.getPlaceholder().height(), legendWidth = target.children().filter(".legend").children().width() || 0; ctx = newCtx; // WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE! // When combining smaller slices into an 'other' slice, we need to // add a new series. Since Flot gives plugins no way to modify the // list of series, the pie plugin uses a hack where the first call // to processDatapoints results in a call to setData with the new // list of series, then subsequent processDatapoints do nothing. // The plugin-global 'processed' flag is used to control this hack; // it starts out false, and is set to true after the first call to // processDatapoints. // Unfortunately this turns future setData calls into no-ops; they // call processDatapoints, the flag is true, and nothing happens. // To fix this we'll set the flag back to false here in draw, when // all series have been processed, so the next sequence of calls to // processDatapoints once again starts out with a slice-combine. // This is really a hack; in 0.9 we need to give plugins a proper // way to modify series before any processing begins. processed = false; // calculate maximum radius and center point maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2; centerTop = canvasHeight / 2 + options.series.pie.offset.top; centerLeft = canvasWidth / 2; if (options.series.pie.offset.left == "auto") { if (options.legend.position.match("w")) { centerLeft += legendWidth / 2; } else { centerLeft -= legendWidth / 2; } if (centerLeft < maxRadius) { centerLeft = maxRadius; } else if (centerLeft > canvasWidth - maxRadius) { centerLeft = canvasWidth - maxRadius; } } else { centerLeft += options.series.pie.offset.left; } var slices = plot.getData(), attempts = 0; // Keep shrinking the pie's radius until drawPie returns true, // indicating that all the labels fit, or we try too many times. do { if (attempts > 0) { maxRadius *= REDRAW_SHRINK; } attempts += 1; clear(); if (options.series.pie.tilt <= 0.8) { drawShadow(); } } while (!drawPie() && attempts < REDRAW_ATTEMPTS) if (attempts >= REDRAW_ATTEMPTS) { clear(); target.prepend("
Could not draw pie with labels contained inside canvas
"); } 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, canvasWidth, canvasHeight); target.children().filter(".pieLabel, .pieLabelBackground").remove(); } function drawShadow() { var shadowLeft = options.series.pie.shadow.left; var shadowTop = options.series.pie.shadow.top; var edge = 10; var alpha = options.series.pie.shadow.alpha; var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 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.pie.tilt); //radius -= edge; for (var i = 1; i <= edge; i++) { ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2, false); ctx.fill(); radius -= i; } ctx.restore(); } function drawPie() { var startAngle = Math.PI * options.series.pie.startAngle; var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; // center and rotate to starting position ctx.save(); ctx.translate(centerLeft,centerTop); ctx.scale(1, options.series.pie.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 if (options.series.pie.stroke.width > 0) { ctx.save(); ctx.lineWidth = options.series.pie.stroke.width; currentAngle = startAngle; for (var i = 0; i < slices.length; ++i) { drawSlice(slices[i].angle, options.series.pie.stroke.color, false); } ctx.restore(); } // draw donut hole drawDonutHole(ctx); ctx.restore(); // Draw the labels, returning true if they fit within the plot if (options.series.pie.label.show) { return drawLabels(); } else return true; function drawSlice(angle, color, fill) { if (angle <= 0 || isNaN(angle)) { return; } if (fill) { ctx.fillStyle = color; } else { ctx.strokeStyle = color; ctx.lineJoin = "round"; } ctx.beginPath(); if (Math.abs(angle - Math.PI * 2) > 0.000000001) { ctx.moveTo(0, 0); // Center of the pie } //ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera ctx.arc(0, 0, radius,currentAngle, currentAngle + angle / 2, false); ctx.arc(0, 0, radius,currentAngle + angle / 2, 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; var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius; for (var i = 0; i < slices.length; ++i) { if (slices[i].percent >= options.series.pie.label.threshold * 100) { if (!drawLabel(slices[i], currentAngle, i)) { return false; } } currentAngle += slices[i].angle; } return true; function drawLabel(slice, startAngle, index) { if (slice.data[0][1] == 0) { return true; } // format label text var lf = options.legend.labelFormatter, text, plf = options.series.pie.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.pie.tilt; var html = "" + text + ""; 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 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) { return false; } if (options.series.pie.label.background.opacity != 0) { // put in the transparent background separately to avoid blended labels and label boxes var c = options.series.pie.label.background.color; if (c == null) { c = slice.color; } var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;"; $("
") .css("opacity", options.series.pie.label.background.opacity) .insertBefore(label); } return true; } // end individual label function } // end drawLabels function } // end drawPie function } // end draw function // Placed here because it needs to be accessed from multiple locations function drawDonutHole(layer) { if (options.series.pie.innerRadius > 0) { // subtract the center layer.save(); var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.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.pie.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.pie.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 pie 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.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius, x, y; for (var i = 0; i < slices.length; ++i) { var s = slices[i]; if (s.pie.show) { ctx.save(); ctx.beginPath(); ctx.moveTo(0, 0); // Center of the pie //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here. ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false); ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false); ctx.closePath(); x = mouseX - centerLeft; y = mouseY - centerTop; if (ctx.isPointInPath) { if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) { 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. var 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 pie 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(); var canvasX = parseInt(e.pageX - offset.left); var canvasY = parseInt(e.pageY - offset.top); var 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) { var options = plot.getOptions(); var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; octx.save(); octx.translate(centerLeft, centerTop); octx.scale(1, options.series.pie.tilt); for (var i = 0; i < highlights.length; ++i) { drawHighlight(highlights[i].series); } drawDonutHole(octx); octx.restore(); function drawHighlight(series) { if (series.angle <= 0 || isNaN(series.angle)) { return; } //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString(); octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor octx.beginPath(); if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) { octx.moveTo(0, 0); // Center of the pie } octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false); octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false); octx.closePath(); octx.fill(); } } } // end init (plugin body) // define pie specific options and their default values var options = { series: { pie: { show: false, radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) innerRadius: 0, /* for donut */ startAngle: 3/2, tilt: 1, shadow: { left: 5, // shadow left offset top: 15, // shadow top offset alpha: 0.02 // shadow alpha }, offset: { top: 0, left: "auto" }, stroke: { color: "#fff", width: 1 }, label: { show: "auto", formatter: function(label, slice) { return "
" + label + "
" + Math.round(slice.percent) + "%
"; }, // 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: "pie", version: "1.1" }); })(jQuery);