summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2018-02-04 04:15:04 +0200
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>2018-02-04 04:15:04 +0200
commit8b7cd623aa59ae5f2fc9057cf8986fcef1d8a55f (patch)
tree04d89f43fa5337b0bf5aff55f29e0e66636e5887 /web
parente1dff0634539ce63ab6d563263c1bcd45c12a96e (diff)
even more d3pie optimizations
Diffstat (limited to 'web')
-rw-r--r--web/dashboard.js2
-rw-r--r--web/lib/d3pie-0.2.1-netdata-2.js3739
2 files changed, 1871 insertions, 1870 deletions
diff --git a/web/dashboard.js b/web/dashboard.js
index 5329d1ae32..112a4054c4 100644
--- a/web/dashboard.js
+++ b/web/dashboard.js
@@ -243,7 +243,7 @@ var NETDATA = window.NETDATA || {};
NETDATA.raphael_js = NETDATA.serverStatic + 'lib/raphael-2.2.4-min.js';
NETDATA.c3_js = NETDATA.serverStatic + 'lib/c3-0.4.18.min.js';
NETDATA.c3_css = NETDATA.serverStatic + 'css/c3-0.4.18.min.css';
- NETDATA.d3pie_js = NETDATA.serverStatic + 'lib/d3pie-0.2.1-netdata-2.js?v7';
+ NETDATA.d3pie_js = NETDATA.serverStatic + 'lib/d3pie-0.2.1-netdata-2.js?v26';
NETDATA.d3_js = NETDATA.serverStatic + 'lib/d3-4.12.2.min.js';
NETDATA.morris_js = NETDATA.serverStatic + 'lib/morris-0.5.1.min.js';
NETDATA.morris_css = NETDATA.serverStatic + 'css/morris-0.5.1.css';
diff --git a/web/lib/d3pie-0.2.1-netdata-2.js b/web/lib/d3pie-0.2.1-netdata-2.js
index 084756c7e6..e6ef064af6 100644
--- a/web/lib/d3pie-0.2.1-netdata-2.js
+++ b/web/lib/d3pie-0.2.1-netdata-2.js
@@ -21,1207 +21,1206 @@
}
}(this, function() {
- var _scriptName = "d3pie";
- var _version = "0.2.1";
+ var _scriptName = "d3pie";
+ var _version = "0.2.1";
- // used to uniquely generate IDs and classes, ensuring no conflict between multiple pies on the same page
- var _uniqueIDCounter = 0;
+ // used to uniquely generate IDs and classes, ensuring no conflict between multiple pies on the same page
+ var _uniqueIDCounter = 0;
- // this section includes all helper libs on the d3pie object. They're populated via grunt-template. Note: to keep
- // the syntax highlighting from getting all messed up, I commented out each line. That REQUIRES each of the files
- // to have an empty first line. Crumby, yes, but acceptable.
- //// --------- _default-settings.js -----------/**
+ // this section includes all helper libs on the d3pie object. They're populated via grunt-template. Note: to keep
+ // the syntax highlighting from getting all messed up, I commented out each line. That REQUIRES each of the files
+ // to have an empty first line. Crumby, yes, but acceptable.
+ //// --------- _default-settings.js -----------/**
/**
* Contains the out-the-box settings for the script. Any of these settings that aren't explicitly overridden for the
* d3pie instance will inherit from these. This is also included on the main website for use in the generation script.
*/
var defaultSettings = {
- header: {
- title: {
- text: "",
- color: "#333333",
- fontSize: 18,
- fontWeight: "bold",
- font: "arial"
- },
- subtitle: {
- text: "",
- color: "#666666",
- fontSize: 14,
- fontWeight: "bold",
- font: "arial"
- },
- location: "top-center",
- titleSubtitlePadding: 8
- },
- footer: {
- text: "",
- color: "#666666",
- fontSize: 14,
- fontWeight: "bold",
- font: "arial",
- location: "left"
- },
- size: {
- canvasHeight: 500,
- canvasWidth: 500,
- pieInnerRadius: "0%",
- pieOuterRadius: null
- },
- data: {
- sortOrder: "none",
- ignoreSmallSegments: {
- enabled: false,
- valueType: "percentage",
- value: null
- },
- smallSegmentGrouping: {
- enabled: false,
- value: 1,
- valueType: "percentage",
- label: "Other",
- color: "#cccccc"
- },
- content: []
- },
- labels: {
- outer: {
- format: "label",
- hideWhenLessThanPercentage: null,
- pieDistance: 30
- },
- inner: {
- format: "percentage",
- hideWhenLessThanPercentage: null
- },
- mainLabel: {
- color: "#333333",
- font: "arial",
- fontWeight: "normal",
- fontSize: 10
- },
- percentage: {
- color: "#dddddd",
- font: "arial",
- fontWeight: "bold",
- fontSize: 10,
- decimalPlaces: 0
- },
- value: {
- color: "#cccc44",
- fontWeight: "bold",
- font: "arial",
- fontSize: 10
- },
- lines: {
- enabled: true,
- style: "curved",
- color: "segment"
- },
- truncation: {
- enabled: false,
- truncateLength: 30
- },
+ header: {
+ title: {
+ text: "",
+ color: "#333333",
+ fontSize: 18,
+ fontWeight: "bold",
+ font: "arial"
+ },
+ subtitle: {
+ text: "",
+ color: "#666666",
+ fontSize: 14,
+ fontWeight: "bold",
+ font: "arial"
+ },
+ location: "top-center",
+ titleSubtitlePadding: 8
+ },
+ footer: {
+ text: "",
+ color: "#666666",
+ fontSize: 14,
+ fontWeight: "bold",
+ font: "arial",
+ location: "left"
+ },
+ size: {
+ canvasHeight: 500,
+ canvasWidth: 500,
+ pieInnerRadius: "0%",
+ pieOuterRadius: null
+ },
+ data: {
+ sortOrder: "none",
+ ignoreSmallSegments: {
+ enabled: false,
+ valueType: "percentage",
+ value: null
+ },
+ smallSegmentGrouping: {
+ enabled: false,
+ value: 1,
+ valueType: "percentage",
+ label: "Other",
+ color: "#cccccc"
+ },
+ content: []
+ },
+ labels: {
+ outer: {
+ format: "label",
+ hideWhenLessThanPercentage: null,
+ pieDistance: 30
+ },
+ inner: {
+ format: "percentage",
+ hideWhenLessThanPercentage: null
+ },
+ mainLabel: {
+ color: "#333333",
+ font: "arial",
+ fontWeight: "normal",
+ fontSize: 10
+ },
+ percentage: {
+ color: "#dddddd",
+ font: "arial",
+ fontWeight: "bold",
+ fontSize: 10,
+ decimalPlaces: 0
+ },
+ value: {
+ color: "#cccc44",
+ fontWeight: "bold",
+ font: "arial",
+ fontSize: 10
+ },
+ lines: {
+ enabled: true,
+ style: "curved",
+ color: "segment"
+ },
+ truncation: {
+ enabled: false,
+ truncateLength: 30
+ },
formatter: null
- },
- effects: {
- load: {
- effect: "none", // "default", commented in the code
- speed: 1000
- },
- pullOutSegmentOnClick: {
- effect: "none", // "bounce", commented in the code
- speed: 300,
- size: 10
- },
- highlightSegmentOnMouseover: false,
- highlightLuminosity: -0.2
- },
- tooltips: {
- enabled: false,
- type: "placeholder", // caption|placeholder
- string: "",
- placeholderParser: null,
- styles: {
- fadeInSpeed: 250,
- backgroundColor: "#000000",
- backgroundOpacity: 0.5,
- color: "#efefef",
- borderRadius: 2,
- font: "arial",
- fontWeight: "bold",
- fontSize: 10,
- padding: 4
- }
- },
- misc: {
- colors: {
- background: null,
- segments: [
- "#2484c1", "#65a620", "#7b6888", "#a05d56", "#961a1a", "#d8d23a", "#e98125", "#d0743c", "#635222", "#6ada6a",
- "#0c6197", "#7d9058", "#207f33", "#44b9b0", "#bca44a", "#e4a14b", "#a3acb2", "#8cc3e9", "#69a6f9", "#5b388f",
- "#546e91", "#8bde95", "#d2ab58", "#273c71", "#98bf6e", "#4daa4b", "#98abc5", "#cc1010", "#31383b", "#006391",
- "#c2643f", "#b0a474", "#a5a39c", "#a9c2bc", "#22af8c", "#7fcecf", "#987ac6", "#3d3b87", "#b77b1c", "#c9c2b6",
- "#807ece", "#8db27c", "#be66a2", "#9ed3c6", "#00644b", "#005064", "#77979f", "#77e079", "#9c73ab", "#1f79a7"
- ],
- segmentStroke: "#ffffff"
- },
- gradient: {
- enabled: false,
- percentage: 95,
- color: "#000000"
- },
- canvasPadding: {
- top: 5,
- right: 5,
- bottom: 5,
- left: 5
- },
- pieCenterOffset: {
- x: 0,
- y: 0
- },
- cssPrefix: null
- },
- callbacks: {
- onload: null,
- onMouseoverSegment: null,
- onMouseoutSegment: null,
- onClickSegment: null
- }
+ },
+ effects: {
+ load: {
+ effect: "none", // "default", commented in the code
+ speed: 1000
+ },
+ pullOutSegmentOnClick: {
+ effect: "none", // "bounce", commented in the code
+ speed: 300,
+ size: 10
+ },
+ highlightSegmentOnMouseover: false,
+ highlightLuminosity: -0.2
+ },
+ tooltips: {
+ enabled: false,
+ type: "placeholder", // caption|placeholder
+ string: "",
+ placeholderParser: null,
+ styles: {
+ fadeInSpeed: 250,
+ backgroundColor: "#000000",
+ backgroundOpacity: 0.5,
+ color: "#efefef",
+ borderRadius: 2,
+ font: "arial",
+ fontWeight: "bold",
+ fontSize: 10,
+ padding: 4
+ }
+ },
+ misc: {
+ colors: {
+ background: null,
+ segments: [
+ "#2484c1", "#65a620", "#7b6888", "#a05d56", "#961a1a", "#d8d23a", "#e98125", "#d0743c", "#635222", "#6ada6a",
+ "#0c6197", "#7d9058", "#207f33", "#44b9b0", "#bca44a", "#e4a14b", "#a3acb2", "#8cc3e9", "#69a6f9", "#5b388f",
+ "#546e91", "#8bde95", "#d2ab58", "#273c71", "#98bf6e", "#4daa4b", "#98abc5", "#cc1010", "#31383b", "#006391",
+ "#c2643f", "#b0a474", "#a5a39c", "#a9c2bc", "#22af8c", "#7fcecf", "#987ac6", "#3d3b87", "#b77b1c", "#c9c2b6",
+ "#807ece", "#8db27c", "#be66a2", "#9ed3c6", "#00644b", "#005064", "#77979f", "#77e079", "#9c73ab", "#1f79a7"
+ ],
+ segmentStroke: "#ffffff"
+ },
+ gradient: {
+ enabled: false,
+ percentage: 95,
+ color: "#000000"
+ },
+ canvasPadding: {
+ top: 5,
+ right: 5,
+ bottom: 5,
+ left: 5
+ },
+ pieCenterOffset: {
+ x: 0,
+ y: 0
+ },
+ cssPrefix: null
+ },
+ callbacks: {
+ onload: null,
+ onMouseoverSegment: null,
+ onMouseoutSegment: null,
+ onClickSegment: null
+ }
};
- //// --------- validate.js -----------
+ //// --------- validate.js -----------
var validate = {
- // called whenever a new pie chart is created
- initialCheck: function(pie) {
- var cssPrefix = pie.cssPrefix;
- var element = pie.element;
- var options = pie.options;
-
- // confirm d3 is available [check minimum version]
- if (!window.d3 || !window.d3.hasOwnProperty("version")) {
- console.error("d3pie error: d3 is not available");
- return false;
- }
-
- // confirm element is either a DOM element or a valid string for a DOM element
- if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
- console.error("d3pie error: the first d3pie() param must be a valid DOM element (not jQuery) or a ID string.");
- return false;
- }
-
- // confirm the CSS prefix is valid. It has to start with a-Z and contain nothing but a-Z0-9_-
- if (!(/[a-zA-Z][a-zA-Z0-9_-]*$/.test(cssPrefix))) {
- console.error("d3pie error: invalid options.misc.cssPrefix");
- return false;
- }
-
- // confirm some data has been supplied
- if (!helpers.isArray(options.data.content)) {
- console.error("d3pie error: invalid config structure: missing data.content property.");
- return false;
- }
- if (options.data.content.length === 0) {
- console.error("d3pie error: no data supplied.");
- return false;
- }
-
- // clear out any invalid data. Each data row needs a valid positive number and a label
- var data = [];
- for (var i=0; i<options.data.content.length; i++) {
- if (typeof options.data.content[i].value !== "number" || isNaN(options.data.content[i].value)) {
- console.log("not valid: ", options.data.content[i]);
- continue;
- }
- if (options.data.content[i].value <= 0) {
- console.log("not valid - should have positive value: ", options.data.content[i]);
- continue;
- }
- data.push(options.data.content[i]);
- }
- pie.options.data.content = data;
-
- // labels.outer.hideWhenLessThanPercentage - 1-100
- // labels.inner.hideWhenLessThanPercentage - 1-100
-
- return true;
- }
+ // called whenever a new pie chart is created
+ initialCheck: function(pie) {
+ var cssPrefix = pie.cssPrefix;
+ var element = pie.element;
+ var options = pie.options;
+
+ // confirm d3 is available [check minimum version]
+ if (!window.d3 || !window.d3.hasOwnProperty("version")) {
+ console.error("d3pie error: d3 is not available");
+ return false;
+ }
+
+ // confirm element is either a DOM element or a valid string for a DOM element
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
+ console.error("d3pie error: the first d3pie() param must be a valid DOM element (not jQuery) or a ID string.");
+ return false;
+ }
+
+ // confirm the CSS prefix is valid. It has to start with a-Z and contain nothing but a-Z0-9_-
+ if (!(/[a-zA-Z][a-zA-Z0-9_-]*$/.test(cssPrefix))) {
+ console.error("d3pie error: invalid options.misc.cssPrefix");
+ return false;
+ }
+
+ // confirm some data has been supplied
+ if (!helpers.isArray(options.data.content)) {
+ console.error("d3pie error: invalid config structure: missing data.content property.");
+ return false;
+ }
+ if (options.data.content.length === 0) {
+ console.error("d3pie error: no data supplied.");
+ return false;
+ }
+
+ // clear out any invalid data. Each data row needs a valid positive number and a label
+ var data = [];
+ for (var i=0; i<options.data.content.length; i++) {
+ if (typeof options.data.content[i].value !== "number" || isNaN(options.data.content[i].value)) {
+ console.log("not valid: ", options.data.content[i]);
+ continue;
+ }
+ if (options.data.content[i].value <= 0) {
+ console.log("not valid - should have positive value: ", options.data.content[i]);
+ continue;
+ }
+ data.push(options.data.content[i]);
+ }
+ pie.options.data.content = data;
+
+ // labels.outer.hideWhenLessThanPercentage - 1-100
+ // labels.inner.hideWhenLessThanPercentage - 1-100
+
+ return true;
+ }
};
- //// --------- helpers.js -----------
+ //// --------- helpers.js -----------
var helpers = {
- // creates the SVG element
- addSVGSpace: function(pie) {
- var element = pie.element;
- var canvasWidth = pie.options.size.canvasWidth;
- var canvasHeight = pie.options.size.canvasHeight;
- var backgroundColor = pie.options.misc.colors.background;
-
- var svg = d3.select(element).append("svg:svg")
- .attr("width", canvasWidth)
- .attr("height", canvasHeight);
-
- if (backgroundColor !== "transparent") {
- svg.style("background-color", function() { return backgroundColor; });
- }
-
- return svg;
- },
-
- shuffleArray: function(array) {
- var currentIndex = array.length, tmpVal, randomIndex;
-
- while (0 !== currentIndex) {
- randomIndex = Math.floor(Math.random() * currentIndex);
- currentIndex -= 1;
-
- // and swap it with the current element
- tmpVal = array[currentIndex];
- array[currentIndex] = array[randomIndex];
- array[randomIndex] = tmpVal;
- }
- return array;
- },
-
- processObj: function(obj, is, value) {
- if (typeof is === 'string') {
- return helpers.processObj(obj, is.split('.'), value);
- } else if (is.length === 1 && value !== undefined) {
+ // creates the SVG element
+ addSVGSpace: function(pie) {
+ var element = pie.element;
+ var canvasWidth = pie.options.size.canvasWidth;
+ var canvasHeight = pie.options.size.canvasHeight;
+ var backgroundColor = pie.options.misc.colors.background;
+
+ var svg = d3.select(element).append("svg:svg")
+ .attr("width", canvasWidth)
+ .attr("height", canvasHeight);
+
+ if (backgroundColor !== "transparent") {
+ svg.style("background-color", function() { return backgroundColor; });
+ }
+
+ return svg;
+ },
+
+ shuffleArray: function(array) {
+ var currentIndex = array.length, tmpVal, randomIndex;
+
+ while (0 !== currentIndex) {
+ randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex -= 1;
+
+ // and swap it with the current element
+ tmpVal = array[currentIndex];
+ array[currentIndex] = array[randomIndex];
+ array[randomIndex] = tmpVal;
+ }
+ return array;
+ },
+
+ processObj: function(obj, is, value) {
+ if (typeof is === 'string') {
+ return helpers.processObj(obj, is.split('.'), value);
+ } else if (is.length === 1 && value !== undefined) {
obj[is[0]] = value;
- return obj[is[0]];
- } else if (is.length === 0) {
- return obj;
- } else {
- return helpers.processObj(obj[is[0]], is.slice(1), value);
- }
- },
-
- getDimensions: function(el) {
- if(typeof el === 'string')
- el = document.getElementById(el);
-
- var w = 0, h = 0;
- if (el) {
- var dimensions = el.getBBox();
- w = dimensions.width;
- h = dimensions.height;
- }
- else {
- console.log("error: getDimensions() " + id + " not found.");
- }
-
- return { w: w, h: h };
- },
-
- /**
- * This is based on the SVG coordinate system, where top-left is 0,0 and bottom right is n-n.
- * @param r1
- * @param r2
- * @returns {boolean}
- */
- rectIntersect: function(r1, r2) {
- var returnVal = (
- // r2.left > r1.right
- (r2.x > (r1.x + r1.w)) ||
-
- // r2.right < r1.left
- ((r2.x + r2.w) < r1.x) ||
-
- // r2.top < r1.bottom
- ((r2.y + r2.h) < r1.y) ||
-
- // r2.bottom > r1.top
- (r2.y > (r1.y + r1.h))
- );
-
- return !returnVal;
- },
-
- /**
- * Returns a lighter/darker shade of a hex value, based on a luminance value passed.
- * @param hex a hex color value such as “#abc” or “#123456″ (the hash is optional)
- * @param lum the luminosity factor: -0.1 is 10% darker, 0.2 is 20% lighter, etc.
- * @returns {string}
- */
- getColorShade: function(hex, lum) {
-
- // validate hex string
- hex = String(hex).replace(/[^0-9a-f]/gi, '');
- if (hex.length < 6) {
- hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
- }
- lum = lum || 0;
-
- // convert to decimal and change luminosity
- var newHex = "#";
- for (var i=0; i<3; i++) {
- var c = parseInt(hex.substr(i * 2, 2), 16);
- c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
- newHex += ("00" + c).substr(c.length);
- }
-
- return newHex;
- },
-
- /**
- * Users can choose to specify segment colors in three ways (in order of precedence):
- * 1. include a "color" attribute for each row in data.content
- * 2. include a misc.colors.segments property which contains an array of hex codes
- * 3. specify nothing at all and rely on this lib provide some reasonable defaults
- *
- * This function sees what's included and populates this.options.colors with whatever's required
- * for this pie chart.
- * @param data
- */
- initSegmentColors: function(pie) {
- var data = pie.options.data.content;
- var colors = pie.options.misc.colors.segments;
-
- // TODO this needs a ton of error handling
-
- var finalColors = [];
- for (var i=0; i<data.length; i++) {
- if (data[i].hasOwnProperty("color")) {
- finalColors.push(data[i].color);
- } else {
- finalColors.push(colors[i]);
- }
- }
-
- return finalColors;
- },
-
- applySmallSegmentGrouping: function(data, smallSegmentGrouping) {
- var totalSize;
- if (smallSegmentGrouping.valueType === "percentage") {
- totalSize = math.getTotalPieSize(data);
- }
-
- // loop through each data item
- var newData = [];
- var groupedData = [];
- var totalGroupedData = 0;
- for (var i=0; i<data.length; i++) {
- if (smallSegmentGrouping.valueType === "percentage") {
- var dataPercent = (data[i].value / totalSize) * 100;
- if (dataPercent <= smallSegmentGrouping.value) {
- groupedData.push(data[i]);
- totalGroupedData += data[i].value;
- continue;
- }
- data[i].isGrouped = false;
- newData.push(data[i]);
- } else {
- if (data[i].value <= smallSegmentGrouping.value) {
- groupedData.push(data[i]);
- totalGroupedData += data[i].value;
- continue;
- }
- data[i].isGrouped = false;
- newData.push(data[i]);
- }
- }
-
- // we're done! See if there's any small segment groups to add
- if (groupedData.length) {
- newData.push({
- color: smallSegmentGrouping.color,
- label: smallSegmentGrouping.label,
- value: totalGroupedData,
- isGrouped: true,
- groupedData: groupedData
- });
- }
-
- return newData;
- },
-
- // for debugging
- showPoint: function(svg, x, y) {
- svg.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).style("fill", "black");
- },
-
- isFunction: function(functionToCheck) {
- var getType = {};
- return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
- },
-
- isArray: function(o) {
- return Object.prototype.toString.call(o) === '[object Array]';
- }
+ return obj[is[0]];
+ } else if (is.length === 0) {
+ return obj;
+ } else {
+ return helpers.processObj(obj[is[0]], is.slice(1), value);
+ }
+ },
+
+ getDimensions: function(el) {
+ if(typeof el === 'string')
+ el = document.getElementById(el);
+
+ var w = 0, h = 0;
+ if (el) {
+ var dimensions = el.getBBox();
+ w = dimensions.width;
+ h = dimensions.height;
+ }
+ else {
+ console.log("error: getDimensions() " + id + " not found.");
+ }
+
+ return { w: w, h: h };
+ },
+
+ /**
+ * This is based on the SVG coordinate system, where top-left is 0,0 and bottom right is n-n.
+ * @param r1
+ * @param r2
+ * @returns {boolean}
+ */
+ rectIntersect: function(r1, r2) {
+ var returnVal = (
+ // r2.left > r1.right
+ (r2.x > (r1.x + r1.w)) ||
+
+ // r2.right < r1.left
+ ((r2.x + r2.w) < r1.x) ||
+
+ // r2.top < r1.bottom
+ ((r2.y + r2.h) < r1.y) ||
+
+ // r2.bottom > r1.top
+ (r2.y > (r1.y + r1.h))
+ );
+
+ return !returnVal;
+ },
+
+ /**
+ * Returns a lighter/darker shade of a hex value, based on a luminance value passed.
+ * @param hex a hex color value such as “#abc” or “#123456″ (the hash is optional)
+ * @param lum the luminosity factor: -0.1 is 10% darker, 0.2 is 20% lighter, etc.
+ * @returns {string}
+ */
+ getColorShade: function(hex, lum) {
+
+ // validate hex string
+ hex = String(hex).replace(/[^0-9a-f]/gi, '');
+ if (hex.length < 6) {
+ hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
+ }
+ lum = lum || 0;
+
+ // convert to decimal and change luminosity
+ var newHex = "#";
+ for (var i=0; i<3; i++) {
+ var c = parseInt(hex.substr(i * 2, 2), 16);
+ c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
+ newHex += ("00" + c).substr(c.length);
+ }
+
+ return newHex;
+ },
+
+ /**
+ * Users can choose to specify segment colors in three ways (in order of precedence):
+ * 1. include a "color" attribute for each row in data.content
+ * 2. include a misc.colors.segments property which contains an array of hex codes
+ * 3. specify nothing at all and rely on this lib provide some reasonable defaults
+ *
+ * This function sees what's included and populates this.options.colors with whatever's required
+ * for this pie chart.
+ * @param data
+ */
+ initSegmentColors: function(pie) {
+ var data = pie.options.data.content;
+ var colors = pie.options.misc.colors.segments;
+
+ // TODO this needs a ton of error handling
+
+ var finalColors = [];
+ for (var i=0; i<data.length; i++) {
+ if (data[i].hasOwnProperty("color")) {
+ finalColors.push(data[i].color);
+ } else {
+ finalColors.push(colors[i]);
+ }
+ }
+
+ return finalColors;
+ },
+
+ applySmallSegmentGrouping: function(data, smallSegmentGrouping) {
+ var totalSize;
+ if (smallSegmentGrouping.valueType === "percentage") {
+ totalSize = math.getTotalPieSize(data);
+ }
+
+ // loop through each data item
+ var newData = [];
+ var groupedData = [];
+ var totalGroupedData = 0;
+ for (var i=0; i<data.length; i++) {
+ if (smallSegmentGrouping.valueType === "percentage") {
+ var dataPercent = (data[i].value / totalSize) * 100;
+ if (dataPercent <= smallSegmentGrouping.value) {
+ groupedData.push(data[i]);
+ totalGroupedData += data[i].value;
+ continue;
+ }
+ data[i].isGrouped = false;
+ newData.push(data[i]);
+ } else {
+ if (data[i].value <= smallSegmentGrouping.value) {
+ groupedData.push(data[i]);
+ totalGroupedData += data[i].value;
+ continue;
+ }
+ data[i].isGrouped = false;
+ newData.push(data[i]);
+ }
+ }
+
+ // we're done! See if there's any small segment groups to add
+ if (groupedData.length) {
+ newData.push({
+ color: smallSegmentGrouping.color,
+ label: smallSegmentGrouping.label,
+ value: totalGroupedData,
+ isGrouped: true,
+ groupedData: groupedData
+ });
+ }
+
+ return newData;
+ },
+
+ // for debugging
+ showPoint: function(svg, x, y) {
+ svg.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).style("fill", "black");
+ },
+
+ isFunction: function(functionToCheck) {
+ var getType = {};
+ return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
+ },
+
+ isArray: function(o) {
+ return Object.prototype.toString.call(o) === '[object Array]';
+ }
};
// taken from jQuery
var extend = function() {
- var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false,
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- class2type = {
- "[object Boolean]": "boolean",
- "[object Number]": "number",
- "[object String]": "string",
- "[object Function]": "function",
- "[object Array]": "array",
- "[object Date]": "date",
- "[object RegExp]": "regexp",
- "[object Object]": "object"
- },
-
- jQuery = {
- isFunction: function (obj) {
- return jQuery.type(obj) === "function";
- },
- isArray: Array.isArray ||
- function (obj) {
- return jQuery.type(obj) === "array";
- },
- isWindow: function (obj) {
- return obj !== null && obj === obj.window;
- },
- isNumeric: function (obj) {
- return !isNaN(parseFloat(obj)) && isFinite(obj);
- },
- type: function (obj) {
- return obj === null ? String(obj) : class2type[toString.call(obj)] || "object";
- },
- isPlainObject: function (obj) {
- if (!obj || jQuery.type(obj) !== "object" || obj.nodeType) {
- return false;
- }
- try {
- if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
- return false;
- }
- } catch (e) {
- return false;
- }
- var key;
- for (key in obj) {}
- return key === undefined || hasOwn.call(obj, key);
- }
- };
- if (typeof target === "boolean") {
- deep = target;
- target = arguments[1] || {};
- i = 2;
- }
- if (typeof target !== "object" && !jQuery.isFunction(target)) {
- target = {};
- }
- if (length === i) {
- target = this;
- --i;
- }
- for (i; i < length; i++) {
- if ((options = arguments[i]) !== null) {
- for (name in options) {
- src = target[name];
- copy = options[name];
- if (target === copy) {
- continue;
- }
- if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
- if (copyIsArray) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
- // WARNING: RECURSION
- target[name] = extend(deep, clone, copy);
- } else if (copy !== undefined) {
- target[name] = copy;
- }
- }
- }
- }
- return target;
+ var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false,
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ class2type = {
+ "[object Boolean]": "boolean",
+ "[object Number]": "number",
+ "[object String]": "string",
+ "[object Function]": "function",
+ "[object Array]": "array",
+ "[object Date]": "date",
+ "[object RegExp]": "regexp",
+ "[object Object]": "object"
+ },
+
+ jQuery = {
+ isFunction: function (obj) {
+ return jQuery.type(obj) === "function";
+ },
+ isArray: Array.isArray ||
+ function (obj) {
+ return jQuery.type(obj) === "array";
+ },
+ isWindow: function (obj) {
+ return obj !== null && obj === obj.window;
+ },
+ isNumeric: function (obj) {
+ return !isNaN(parseFloat(obj)) && isFinite(obj);
+ },
+ type: function (obj) {
+ return obj === null ? String(obj) : class2type[toString.call(obj)] || "object";
+ },
+ isPlainObject: function (obj) {
+ if (!obj || jQuery.type(obj) !== "object" || obj.nodeType) {
+ return false;
+ }
+ try {
+ if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
+ return false;
+ }
+ } catch (e) {
+ return false;
+ }
+ var key;
+ for (key in obj) {}
+ return key === undefined || hasOwn.call(obj, key);
+ }
+ };
+ if (typeof target === "boolean") {
+ deep = target;
+ target = arguments[1] || {};
+ i = 2;
+ }
+ if (typeof target !== "object" && !jQuery.isFunction(target)) {
+ target = {};
+ }
+ if (length === i) {
+ target = this;
+ --i;
+ }
+ for (i; i < length; i++) {
+ if ((options = arguments[i]) !== null) {
+ for (name in options) {
+ src = target[name];
+ copy = options[name];
+ if (target === copy) {
+ continue;
+ }
+ if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
+ if (copyIsArray) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+ // WARNING: RECURSION
+ target[name] = extend(deep, clone, copy);
+ } else if (