From a417f507b9cf123050c89dbf940b127091af25ab Mon Sep 17 00:00:00 2001 From: moisseev Date: Sun, 20 Feb 2022 20:36:32 +0300 Subject: [WebUI] Replace pie chart library --- interface/js/app/graph.js | 264 +++++++++++++++++------------------------- interface/js/app/rspamd.js | 103 ++-------------- interface/js/app/stats.js | 92 ++++----------- interface/js/lib/d3pie.min.js | 10 +- interface/js/main.js | 2 +- 5 files changed, 144 insertions(+), 327 deletions(-) (limited to 'interface/js') diff --git a/interface/js/app/graph.js b/interface/js/app/graph.js index 54daf79c1..6bd83c72b 100644 --- a/interface/js/app/graph.js +++ b/interface/js/app/graph.js @@ -25,16 +25,15 @@ /* global d3:false, FooTable:false */ -define(["jquery", "d3evolution", "footable"], - function ($, D3Evolution) { +define(["jquery", "d3evolution", "d3pie", "footable"], + function ($, D3Evolution, D3Pie) { "use strict"; var rrd_pie_config = { - header: {}, + cornerRadius: 2, size: { canvasWidth: 400, canvasHeight: 180, - pieInnerRadius: "20%", pieOuterRadius: "80%" }, labels: { @@ -45,140 +44,118 @@ define(["jquery", "d3evolution", "footable"], hideWhenLessThanPercentage: 8 }, }, - misc: { - pieCenterOffset: { - x: -120, - y: 10, - }, - gradient: { - enabled: true, - }, - }, - }; - - var graph_options = { - title: "Rspamd throughput", - width: 1060, - height: 370, - yAxisLabel: "Message rate, msg/s", - - legend: { - space: 140, - entries: [{ - label: "reject", - color: "#FF0000" - }, { - label: "soft reject", - color: "#BF8040" - }, { - label: "rewrite subject", - color: "#FF6600" - }, { - label: "add header", - color: "#FFAD00" - }, { - label: "greylist", - color: "#436EEE" - }, { - label: "no action", - color: "#66CC00" - }] + padAngle: 0.02, + pieCenterOffset: { + x: -120, + y: 10, } }; - function initGraph(rspamd) { - var graph = new D3Evolution("graph", $.extend({}, graph_options, { - yScale: rspamd.getSelector("selYScale"), - type: rspamd.getSelector("selType"), - interpolate: rspamd.getSelector("selInterpolate"), - convert: rspamd.getSelector("selConvert"), - })); - $("#selYScale").change(function () { - graph.yScale(this.value); - }); - $("#selConvert").change(function () { - graph.convert(this.value); - }); - $("#selType").change(function () { - graph.type(this.value); - }); - $("#selInterpolate").change(function () { - graph.interpolate(this.value); - }); + var ui = {}; + var prevUnit = "msg/s"; - return graph; - } + ui.draw = function (rspamd, graphs, tables, neighbours, checked_server, type) { + var graph_options = { + title: "Rspamd throughput", + width: 1060, + height: 370, + yAxisLabel: "Message rate, msg/s", - function getRrdSummary(json, scaleFactor) { - var xExtents = d3.extent(d3.merge(json), function (d) { return d.x; }); - var timeInterval = xExtents[1] - xExtents[0]; + legend: { + space: 140, + entries: rspamd.chartLegend + } + }; - var total = 0; - var rows = json.map(function (curr, i) { - // Time intervals that don't have data are excluded from average calculation as d3.mean()ignores nulls - var avg = d3.mean(curr, function (d) { return d.y; }); - // To find an integral on the whole time interval we need to convert nulls to zeroes - var value = d3.mean(curr, function (d) { return Number(d.y); }) * timeInterval / scaleFactor ^ 0; // eslint-disable-line no-bitwise - var yExtents = d3.extent(curr, function (d) { return d.y; }); + function initGraph() { + var graph = new D3Evolution("graph", $.extend({}, graph_options, { + yScale: rspamd.getSelector("selYScale"), + type: rspamd.getSelector("selType"), + interpolate: rspamd.getSelector("selInterpolate"), + convert: rspamd.getSelector("selConvert"), + })); + $("#selYScale").change(function () { + graph.yScale(this.value); + }); + $("#selConvert").change(function () { + graph.convert(this.value); + }); + $("#selType").change(function () { + graph.type(this.value); + }); + $("#selInterpolate").change(function () { + graph.interpolate(this.value); + }); - total += value; - return { - label: graph_options.legend.entries[i].label, - value: value, - min: Number(yExtents[0].toFixed(6)), - avg: Number(avg.toFixed(6)), - max: Number(yExtents[1].toFixed(6)), - last: Number(curr[curr.length - 1].y.toFixed(6)), - color: graph_options.legend.entries[i].color, - }; - }, []); + return graph; + } - return { - rows: rows, - total: total - }; - } + function getRrdSummary(json, scaleFactor) { + var xExtents = d3.extent(d3.merge(json), function (d) { return d.x; }); + var timeInterval = xExtents[1] - xExtents[0]; - function initSummaryTable(tables, rows, unit) { - tables.rrd_summary = FooTable.init("#rrd-table", { - sorting: { - enabled: true - }, - columns: [ - {name:"label", title:"Action"}, - {name:"value", title:"Messages", defaultContent:""}, - {name:"min", title:"Minimum, " + unit + "", defaultContent:""}, - {name:"avg", title:"Average, " + unit + "", defaultContent:""}, - {name:"max", title:"Maximum, " + unit + "", defaultContent:""}, - {name:"last", title:"Last, " + unit}, - ], - rows: rows.map(function (curr, i) { + var total = 0; + var rows = json.map(function (curr, i) { + // Time intervals that don't have data are excluded from average calculation as d3.mean()ignores nulls + var avg = d3.mean(curr, function (d) { return d.y; }); + // To find an integral on the whole time interval we need to convert nulls to zeroes + var value = d3.mean(curr, function (d) { return Number(d.y); }) * timeInterval / scaleFactor ^ 0; // eslint-disable-line no-bitwise + var yExtents = d3.extent(curr, function (d) { return d.y; }); + + total += value; return { - options: { - style: { - color: graph_options.legend.entries[i].color - } - }, - value: curr + label: graph_options.legend.entries[i].label, + value: value, + min: Number(yExtents[0].toFixed(6)), + avg: Number(avg.toFixed(6)), + max: Number(yExtents[1].toFixed(6)), + last: Number(curr[curr.length - 1].y.toFixed(6)), + color: graph_options.legend.entries[i].color, }; - }, []) - }); - } + }, []); - function drawRrdTable(tables, rows, unit) { - if (Object.prototype.hasOwnProperty.call(tables, "rrd_summary")) { - $.each(tables.rrd_summary.rows.all, function (i, row) { - row.val(rows[i], false, true); + return { + rows: rows, + total: total + }; + } + + function initSummaryTable(rows, unit) { + tables.rrd_summary = FooTable.init("#rrd-table", { + sorting: { + enabled: true + }, + columns: [ + {name:"label", title:"Action"}, + {name:"value", title:"Messages", defaultContent:""}, + {name:"min", title:"Minimum, " + unit + "", defaultContent:""}, + {name:"avg", title:"Average, " + unit + "", defaultContent:""}, + {name:"max", title:"Maximum, " + unit + "", defaultContent:""}, + {name:"last", title:"Last, " + unit}, + ], + rows: rows.map(function (curr, i) { + return { + options: { + style: { + color: graph_options.legend.entries[i].color + } + }, + value: curr + }; + }, []) }); - } else { - initSummaryTable(tables, rows, unit); } - } - var ui = {}; - var prevUnit = "msg/s"; + function drawRrdTable(rows, unit) { + if (Object.prototype.hasOwnProperty.call(tables, "rrd_summary")) { + $.each(tables.rrd_summary.rows.all, function (i, row) { + row.val(rows[i], false, true); + }); + } else { + initSummaryTable(rows, unit); + } + } - ui.draw = function (rspamd, graphs, tables, neighbours, checked_server, type) { function updateWidgets(data) { var rrd_summary = {rows:[]}; var unit = "msg/s"; @@ -200,39 +177,8 @@ define(["jquery", "d3evolution", "footable"], rrd_summary = getRrdSummary(data, scaleFactor); } - if (graphs.rrd_pie) { - graphs.rrd_pie.destroy(); - delete graphs.rrd_pie; - } - if (rrd_summary.total) { - graphs.rrd_pie = rspamd.drawPie(graphs.rrd_pie, - "rrd-pie", - rrd_summary.rows, - rrd_pie_config); - } else { - // Show grayed out pie as percentage is undefined - graphs.rrd_pie = rspamd.drawPie(graphs.rrd_pie, - "rrd-pie", - [{ - value: 1, - color: "#FFFFFF", - }], - $.extend({}, rrd_pie_config, { - labels: { - outer: { - format: "none" - }, - inner: { - format: "none" - }, - }, - tooltips: { - enabled: true, - string: "Undefined" - }, - }) - ); - } + if (!graphs.rrd_pie) graphs.rrd_pie = new D3Pie("rrd-pie", rrd_pie_config); + graphs.rrd_pie.data(rrd_summary.rows); graphs.graph.data(data); if (unit !== prevUnit) { @@ -240,12 +186,12 @@ define(["jquery", "d3evolution", "footable"], $(".unit").text(unit); prevUnit = unit; } - drawRrdTable(tables, rrd_summary.rows, unit); + drawRrdTable(rrd_summary.rows, unit); document.getElementById("rrd-total-value").innerHTML = rrd_summary.total; } if (!graphs.graph) { - graphs.graph = initGraph(rspamd); + graphs.graph = initGraph(); } rspamd.query("graph", { @@ -295,11 +241,11 @@ define(["jquery", "d3evolution", "footable"], ui.setup = function (rspamd) { // Handling mouse events on overlapping elements $("#rrd-pie").mouseover(function () { - $("#rrd-pie").css("z-index", "200"); + $("#rrd-pie,#rrd-pie-tooltip").css("z-index", "200"); $("#rrd-table_toggle").css("z-index", "300"); }); $("#rrd-table_toggle").mouseover(function () { - $("#rrd-pie").css("z-index", "0"); + $("#rrd-pie,#rrd-pie-tooltip").css("z-index", "0"); $("#rrd-table_toggle").css("z-index", "0"); }); diff --git a/interface/js/app/rspamd.js b/interface/js/app/rspamd.js index 711ec1971..0fe64ecb6 100644 --- a/interface/js/app/rspamd.js +++ b/interface/js/app/rspamd.js @@ -25,13 +25,21 @@ /* global jQuery:false, FooTable:false, Visibility:false */ -define(["jquery", "d3pie", "visibility", "nprogress", "stickytabs", "app/stats", "app/graph", "app/config", +define(["jquery", "visibility", "nprogress", "stickytabs", "app/stats", "app/graph", "app/config", "app/symbols", "app/history", "app/upload", "app/selectors"], // eslint-disable-next-line max-params -function ($, D3pie, visibility, NProgress, stickyTabs, tab_stat, tab_graph, tab_config, +function ($, visibility, NProgress, stickyTabs, tab_stat, tab_graph, tab_config, tab_symbols, tab_history, tab_upload, tab_selectors) { "use strict"; var ui = { + chartLegend: [ + {label: "reject", color: "#FF0000"}, + {label: "soft reject", color: "#BF8040"}, + {label: "rewrite subject", color: "#FF6600"}, + {label: "add header", color: "#FFAD00"}, + {label: "greylist", color: "#436EEE"}, + {label: "no action", color: "#66CC00"} + ], page_size: { scan: 25, errors: 25, @@ -595,97 +603,6 @@ function ($, D3pie, visibility, NProgress, stickyTabs, tab_stat, tab_graph, tab_ }); }; - ui.drawPie = function (object, id, data, conf) { - var obj = object; - if (obj) { - obj.updateProp("data.content", - data.filter(function (elt) { - return elt.value > 0; - }) - ); - } else { - obj = new D3pie(id, - $.extend({}, { - header: { - title: { - text: "Rspamd filter stats", - fontSize: 24, - font: "open sans" - }, - subtitle: { - color: "#999999", - fontSize: 12, - font: "open sans" - }, - titleSubtitlePadding: 9 - }, - footer: { - color: "#999999", - fontSize: 10, - font: "open sans", - location: "bottom-left" - }, - size: { - canvasWidth: 600, - canvasHeight: 400, - pieInnerRadius: "20%", - pieOuterRadius: "85%" - }, - data: { - // "sortOrder": "value-desc", - content: data.filter(function (elt) { - return elt.value > 0; - }) - }, - labels: { - outer: { - hideWhenLessThanPercentage: 1, - pieDistance: 30 - }, - inner: { - hideWhenLessThanPercentage: 4 - }, - mainLabel: { - fontSize: 14 - }, - percentage: { - color: "#eeeeee", - fontSize: 14, - decimalPlaces: 0 - }, - lines: { - enabled: true - }, - truncation: { - enabled: true - } - }, - tooltips: { - enabled: true, - type: "placeholder", - string: "{label}: {value} ({percentage}%)" - }, - effects: { - pullOutSegmentOnClick: { - effect: "back", - speed: 400, - size: 8 - }, - load: { - effect: "none" - } - }, - misc: { - gradient: { - enabled: true, - percentage: 100 - } - } - }, conf)); - } - return obj; - }; - ui.getPassword = getPassword; ui.getSelector = getSelector; diff --git a/interface/js/app/stats.js b/interface/js/app/stats.js index b7194a157..41651550d 100644 --- a/interface/js/app/stats.js +++ b/interface/js/app/stats.js @@ -25,7 +25,7 @@ /* global d3:false */ define(["jquery", "d3pie"], - function ($) { + function ($, D3Pie) { "use strict"; // @ ms to date function msToTime(seconds) { @@ -200,77 +200,35 @@ define(["jquery", "d3pie"], } function getChart(rspamd, graphs, checked_server) { - if (graphs.chart) { - graphs.chart.destroy(); - delete graphs.chart; + if (!graphs.chart) { + graphs.chart = new D3Pie("chart", { + labels: { + outer: { + collideHeight: 18, + } + }, + title: "Rspamd filter stats" + }); } + var data = []; var creds = JSON.parse(sessionStorage.getItem("Credentials")); // Controller doesn't return the 'actions' object until at least one message is scanned - if (!creds || !creds[checked_server] || !creds[checked_server].data.scanned) { - // Show grayed out pie as percentage is undefined - return rspamd.drawPie(graphs.chart, - "chart", - [{ - value: 1, - color: "#ffffff", - label: "undefined" - }], - { - labels: { - mainLabel: { - fontSize: 14, - }, - inner: { - format: "none", - }, - lines: { - color: "#cccccc" - } - }, - tooltips: { - enabled: true, - string: "{label}" - }, - } - ); - } - - var data = creds[checked_server].data.actions; - var new_data = [{ - color: "#66CC00", - label: "no action", - data: data["no action"], - value: data["no action"] - }, { - color: "#BF8040", - label: "soft reject", - data: data["soft reject"], - value: data["soft reject"] - }, { - color: "#FFAD00", - label: "add header", - data: data["add header"], - value: data["add header"] - }, { - color: "#FF6600", - label: "rewrite subject", - data: data["rewrite subject"], - value: data["rewrite subject"] - }, { - color: "#436EEE", - label: "greylist", - data: data.greylist, - value: data.greylist - }, { - color: "#FF0000", - label: "reject", - data: data.reject, - value: data.reject - }]; + if (creds && creds[checked_server] && creds[checked_server].data.scanned) { + var actions = creds[checked_server].data.actions; - return rspamd.drawPie(graphs.chart, "chart", new_data); + ["no action", "soft reject", "add header", "rewrite subject", "greylist", "reject"] + .forEach(function (action) { + data.push({ + color: rspamd.chartLegend.find(function (item) { return item.label === action; }).color, + label: action, + value: actions[action] + }); + }); + } + graphs.chart.data(data); } + // Public API var ui = { statWidgets: function (rspamd, graphs, checked_server) { @@ -363,7 +321,7 @@ define(["jquery", "d3pie"], to_Credentials["All SERVERS"].data = neighbours_sum; sessionStorage.setItem("Credentials", JSON.stringify(to_Credentials)); displayStatWidgets(checked_server); - graphs.chart = getChart(rspamd, graphs, checked_server); + getChart(rspamd, graphs, checked_server); }); }, promises.length ? 100 : 0); }, diff --git a/interface/js/lib/d3pie.min.js b/interface/js/lib/d3pie.min.js index 22842e651..5df14ce53 100644 --- a/interface/js/lib/d3pie.min.js +++ b/interface/js/lib/d3pie.min.js @@ -1,9 +1,5 @@ /*! - * d3pie - * @author Ben Keen - * @version 0.2.1.20170923 (patched by Alexander Moisseev) - * @date 2017-09-23 - * @repo https://github.com/moisseev/d3pie/tree/patched - * @license MIT + * rspamd-D3Pie 0.0.1 (https://github.com/moisseev/rspamd-D3Pie) + * Copyright (c) 2022, Alexander Moisseev, BSD 2-Clause */ -(function(a,b){if(typeof define==="function"&&define.amd){define([],b)}else{if(typeof exports==="object"){module.exports=b()}else{a.d3pie=b(a)}}}(this,function(){var g="d3pie";var f="0.2.1";var p=0;var h={header:{title:{text:"",color:"#333333",fontSize:18,font:"arial"},subtitle:{text:"",color:"#666666",fontSize:14,font:"arial"},location:"top-center",titleSubtitlePadding:8},footer:{text:"",color:"#666666",fontSize:14,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",fontSize:10},percentage:{color:"#dddddd",font:"arial",fontSize:10,decimalPlaces:0},value:{color:"#cccc44",font:"arial",fontSize:10},lines:{enabled:true,style:"curved",color:"segment"},truncation:{enabled:false,truncateLength:30},formatter:null},effects:{load:{effect:"default",speed:1000},pullOutSegmentOnClick:{effect:"bounce",speed:300,size:10},highlightSegmentOnMouseover:true,highlightLuminosity:-0.2},tooltips:{enabled:false,type:"placeholder",string:"",placeholderParser:null,styles:{fadeInSpeed:250,backgroundColor:"#000000",backgroundOpacity:0.5,color:"#efefef",borderRadius:2,font:"arial",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}};var m={initialCheck:function(q){var v=q.cssPrefix;var t=q.element;var r=q.options;if(!window.d3||!window.d3.hasOwnProperty("version")){console.error("d3pie error: d3 is not available");return false}if(!(t instanceof HTMLElement||t instanceof SVGElement)){console.error("d3pie error: the first d3pie() param must be a valid DOM element (not jQuery) or a ID string.");return false}if(!(/[a-zA-Z][a-zA-Z0-9_-]*$/.test(v))){console.error("d3pie error: invalid options.misc.cssPrefix");return false}if(!b.isArray(r.data.content)){console.error("d3pie error: invalid config structure: missing data.content property.");return false}if(r.data.content.length===0){console.error("d3pie error: no data supplied.");return false}var u=[];for(var s=0;sr){clearInterval(q)}s++},1)},whenElementsExist:function(r,u){var t=1;var s=1000;var q=setInterval(function(){var w=true;for(var v=0;vs){clearInterval(q)}t++},1)},shuffleArray:function(t){var s=t.length,r,q;while(0!==s){q=Math.floor(Math.random()*s);s-=1;r=t[s];t[s]=t[q];t[q]=r}return t},processObj:function(s,q,r){if(typeof q==="string"){return b.processObj(s,q.split("."),r)}else{if(q.length===1&&r!==undefined){s[q[0]]=r;return s[q[0]]}else{if(q.length===0){return s}else{return b.processObj(s[q[0]],q.slice(1),r)}}}},getDimensions:function(u){var s=document.getElementById(u);var q=0,r=0;if(s){var t=s.getBBox();q=t.width;r=t.height}else{console.log("error: getDimensions() "+u+" not found.")}return{w:q,h:r}},rectIntersect:function(r,q){var s=((q.x>(r.x+r.w))||((q.x+q.w)(r.y+r.h)));return !s},getColorShade:function(t,r){t=String(t).replace(/[^0-9a-f]/gi,"");if(t.length<6){t=t[0]+t[0]+t[1]+t[1]+t[2]+t[2]}r=r||0;var q="#";for(var s=0;s<3;s++){var u=parseInt(t.substr(s*2,2),16);u=Math.round(Math.min(Math.max(0,u+(u*r)),255)).toString(16);q+=("00"+u).substr(u.length)}return q},initSegmentColors:function(s){var u=s.options.data.content;var r=s.options.misc.colors.segments;var q=[];for(var t=0;t99)?99:x;x=(x<0)?0:x;var r=(z0){r-=s}}v=Math.floor((r/100)*x)/2}else{v=parseInt(A.pieOuterRadius,10)}}if(/%/.test(A.pieInnerRadius)){x=parseInt(A.pieInnerRadius.replace(/[\D]/,""),10);x=(x>99)?99:x;x=(x<0)?0:x;y=Math.floor((v/100)*x)}else{y=parseInt(A.pieInnerRadius,10)}t.innerRadius=y;t.outerRadius=v},getTotalPieSize:function(s){var q=0;for(var r=0;rt.label.toLowerCase())?1:-1});break;case"label-desc":s.sort(function(u,t){return(u.label.toLowerCase()u.truncation.truncateLength){z=A.label.substring(0,u.truncation.truncateLength)+"..."}}return z}).style("font-size",u.mainLabel.fontSize+"px").style("font-family",u.mainLabel.font).style("fill",u.mainLabel.color)}if(q.percentage){s.append("text").attr("id",function(z,y){return r.cssPrefix+"segmentPercentage"+y+"-"+x}).attr("class",r.cssPrefix+"segmentPercentage-"+x).text(function(A,z){var y=A.percentage;if(u.formatter){w.index=z;w.part="percentage";w.value=A.value;w.label=A.percentage;y=u.formatter(w)}else{y+="%"}return y}).style("font-size",u.percentage.fontSize+"px").style("font-family",u.percentage.font).style("fill",u.percentage.color)}if(q.value){s.append("text").attr("id",function(z,y){return r.cssPrefix+"segmentValue"+y+"-"+x}).attr("class",r.cssPrefix+"segmentValue-"+x).text(function(z,y){w.index=y;w.part="value";w.value=z.value;w.label=z.value;return u.formatter?u.formatter(w,z.value):z.value}).style("font-size",u.value.fontSize+"px").style("font-family",u.value.font).style("fill",u.value.color)}},positionLabelElements:function(q,t,r){e["dimensions-"+t]=[];var v=d3.selectAll("."+q.cssPrefix+"labelGroup-"+t);v.each(function(A,x){var z=d3.select(this).selectAll("."+q.cssPrefix+"segmentMainLabel-"+t);var w=d3.select(this).selectAll("."+q.cssPrefix+"segmentPercentage-"+t);var y=d3.select(this).selectAll("."+q.cssPrefix+"segmentValue-"+t);e["dimensions-"+t].push({mainLabel:(z.node()!==null)?z.node().getBBox():null,percentage:(w.node()!==null)?w.node().getBBox():null,value:(y.node()!==null)?y.node().getBBox():null})});var s=5;var u=e["dimensions-"+t];switch(r){case"label-value1":d3.selectAll("."+q.cssPrefix+"segmentValue-"+t).attr("dx",function(x,w){return u[w].mainLabel.width+s});break;case"label-value2":d3.selectAll("."+q.cssPrefix+"segmentValue-"+t).attr("dy",function(x,w){return u[w].mainLabel.height});break;case"label-percentage1":d3.selectAll("."+q.cssPrefix+"segmentPercentage-"+t).attr("dx",function(x,w){return u[w].mainLabel.width+s});break;case"label-percentage2":d3.selectAll("."+q.cssPrefix+"segmentPercentage-"+t).attr("dx",function(x,w){return(u[w].mainLabel.width/2)-(u[w].percentage.width/2)}).attr("dy",function(x,w){return u[w].mainLabel.height});break}},computeLabelLinePositions:function(q){q.lineCoordGroups=[];d3.selectAll("."+q.cssPrefix+"labelGroup-outer").each(function(s,r){return e.computeLinePosition(q,r)})},computeLinePosition:function(y,x){var w=d.getSegmentAngle(x,y.options.data.content,y.totalSize,{midpoint:true});var D=n.rotate(y.pieCenter.x,y.pieCenter.y-y.outerRadius,y.pieCenter.x,y.pieCenter.y,w);var r=y.outerLabelGroupData[x].h/5;var s=6;var u=Math.floor(w/90);var C=4;var t,B,q,A;if(u===2&&w===180){u=1}switch(u){case 0:t=y.outerLabelGroupData[x].x-s-((y.outerLabelGroupData[x].x-s-D.x)/2);B=y.outerLabelGroupData[x].y+((D.y-y.outerLabelGroupData[x].y)/C);q=y.outerLabelGroupData[x].x-s;A=y.outerLabelGroupData[x].y-r;break;case 1:t=D.x+(y.outerLabelGroupData[x].x-D.x)/C;B=D.y+(y.outerLabelGroupData[x].y-D.y)/C;q=y.outerLabelGroupData[x].x-s;A=y.outerLabelGroupData[x].y-r;break;case 2:var v=y.outerLabelGroupData[x].x+y.outerLabelGroupData[x].w+s;t=D.x-(D.x-v)/C;B=D.y+(y.outerLabelGroupData[x].y-D.y)/C;q=y.outerLabelGroupData[x].x+y.outerLabelGroupData[x].w+s;A=y.outerLabelGroupData[x].y-r;break;case 3:var z=y.outerLabelGroupData[x].x+y.outerLabelGroupData[x].w+s;t=z+((D.x-z)/C);B=y.outerLabelGroupData[x].y+(D.y-y.outerLabelGroupData[x].y)/C;q=y.outerLabelGroupData[x].x+y.outerLabelGroupData[x].w+s;A=y.outerLabelGroupData[x].y-r;break}if(y.options.labels.lines.style==="straight"){y.lineCoordGroups[x]=[{x:D.x,y:D.y},{x:q,y:A}]}else{y.lineCoordGroups[x]=[{x:D.x,y:D.y},{x:t,y:B},{x:q,y:A}]}},addLabelLines:function(q){var t=q.svg.insert("g","."+q.cssPrefix+"pieChart").attr("class",q.cssPrefix+"lineGroups").style("opacity",0);var s=t.selectAll("."+q.cssPrefix+"lineGroup").data(q.lineCoordGroups).enter().append("g").attr("class",q.cssPrefix+"lineGroup");var r=d3.line().curve(d3.curveBasis).x(function(u){return u.x}).y(function(u){return u.y});s.append("path").attr("d",r).attr("stroke",function(v,u){return(q.options.labels.lines.color==="segment")?q.options.colors[u]:q.options.labels.lines.color}).attr("stroke-width",1).attr("fill","none").style("opacity",function(x,w){var u=q.options.labels.outer.hideWhenLessThanPercentage;var v=(u!==null&&q.options.data.content[w].percentage0){var t=d.getSegmentAngle(u,q.options.data.content,q.totalSize,{midpoint:true});var D=n.translate(q.pieCenter.x,q.pieCenter.y,q.innerRadius,t);C.x=D.x;C.y=D.y}var B=b.getDimensions(q.cssPrefix+"labelGroup"+u+"-inner");var v=B.w/2;var s=B.h/4;A=C.x+(q.lineCoordGroups[u][0].x-C.x)/1.8;z=C.y+(q.lineCoordGroups[u][0].y-C.y)/1.8;A=A-v;z=z+s}return"translate("+A+","+z+")"})},fadeInLabelsAndLines:function(q){var r=(q.options.effects.load.effect==="default")?q.options.effects.load.speed:1;setTimeout(function(){var s=(q.options.effects.load.effect==="default")?400:1;d3.selectAll("."+q.cssPrefix+"labelGroup-outer").transition().duration(s).style("opacity",function(v,u){var t=q.options.labels.outer.hideWhenLessThanPercentage;return(t!==null&&v.percentage=q;t--){z=u.outerLabelGroupData[t];if(!e.isLabelHidden(u,t)&&b.rectIntersect(z,s)){e.adjustLabelPos(u,w,v,r);break}}}e.checkConflict(u,w,y,A)},isLabelHidden:function(r,s){var q=r.options.labels.outer.hideWhenLessThanPercentage;return(q!==null&&r.options.data.content[s].percentageMath.abs(u)){x=Math.sqrt((w.lineLength*w.lineLength)-(u*u))}else{x=Math.sqrt((u*u)-(w.lineLength*w.lineLength))}if(r.hs==="right"){v=w.center.x+x}else{v=w.center.x-x-s.outerLabelGroupData[q].w}s.outerLabelGroupData[q].x=v;s.outerLabelGroupData[q].y=t},getIdealOuterLabelPositions:function(u,t){var x=d3.select("#"+u.cssPrefix+"labelGroup"+t+"-outer").node();if(!x){return}var s=x.getBBox();var r=d.getSegmentAngle(t,u.options.data.content,u.totalSize,{midpoint:true});var w=u.pieCenter.x;var v=u.pieCenter.y-(u.outerRadius+u.options.labels.outer.pieDistance);var y=n.rotate(w,v,u.pieCenter.x,u.pieCenter.y,r);var q="right";if(r>180){y.x-=(s.width+8);q="left"}else{y.x+=8}u.outerLabelGroupData[t]={x:y.x,y:y.y,w:s.width,h:s.height,hs:q}}};var d={effectMap:{none:d3.easeLinear,bounce:d3.easeBounce,linear:d3.easeLinear,sin:d3.easeSin,elastic:d3.easeElastic,back:d3.easeBack,quad:d3.easeQuad,circle:d3.easeCircle,exp:d3.easeExp},create:function(u){var w=u.pieCenter;var q=u.options.colors;var y=u.options.effects.load;var s=u.options.misc.colors.segmentStroke;var x=u.svg.insert("g","#"+u.cssPrefix+"title").attr("transform",function(){return n.getPieTranslateCenter(w)}).attr("class",u.cssPrefix+"pieChart");var t=d3.arc().innerRadius(u.innerRadius).outerRadius(u.outerRadius).startAngle(0).endAngle(function(z){return(z.value/u.totalSize)*2*Math.PI});var v=x.selectAll("."+u.cssPrefix+"arc").data(u.options.data.content).enter().append("g").attr("class",u.cssPrefix+"arc");var r=y.speed;if(y.effect==="none"){r=0}v.append("path").attr("id",function(A,z){return u.cssPrefix+"segment"+z}).attr("fill",function(B,A){var z=q[A];if(u.options.misc.gradient.enabled){z="url(#"+u.cssPrefix+"grad"+A+")"}return z}).attr("data-index",function(A,z){return z}).style("stroke",s).style("stroke-width",1).transition().ease(d3.easeCubicInOut).duration(r).attrTween("d",function(z){var A=d3.interpolate({value:0},z);return function(B){return u.arc(A(B))}});u.svg.selectAll("g."+u.cssPrefix+"arc").attr("transform",function(B,z){var A=0;if(z>0){A=d.getSegmentAngle(z-1,u.options.data.content,u.totalSize)}return"rotate("+A+")"});u.arc=t},addGradients:function(q){var r=q.svg.append("defs").selectAll("radialGradient").data(q.options.data.content).enter().append("radialGradient").attr("gradientUnits","userSpaceOnUse").attr("cx",0).attr("cy",0).attr("r","120%").attr("id",function(t,s){return q.cssPrefix+"grad"+s});r.append("stop").attr("offset","0%").style("stop-color",function(t,s){return q.options.colors[s]});r.append("stop").attr("offset",q.options.misc.gradient.percentage+"%").style("stop-color",q.options.misc.gradient.color)},addSegmentEventHandlers:function(q){var r=d3.selectAll("."+q.cssPrefix+"arc,."+q.cssPrefix+"labelGroup-inner,."+q.cssPrefix+"labelGroup-outer");r.on("click",function(){var u=d3.select(this);var t;if(u.attr("class")===q.cssPrefix+"arc"){t=u.select("path")}else{var s=u.attr("data-index");t=d3.select("#"+q.cssPrefix+"segment"+s)}var v=t.attr("class")===q.cssPrefix+"expanded";d.onSegmentEvent(q,q.options.callbacks.onClickSegment,t,v);if(q.options.effects.pullOutSegmentOnClick.effect!=="none"){if(v){d.closeSegment(q,t.node())}else{d.openSegment(q,t.node())}}});r.on("mouseover",function(){var v=d3.select(this);var u,s;if(v.attr("class")===q.cssPrefix+"arc"){u=v.select("path")}else{s=v.attr("data-index");u=d3.select("#"+q.cssPrefix+"segment"+s)}if(q.options.effects.highlightSegmentOnMouseover){s=u.attr("data-index");var t=q.options.colors[s];u.style("fill",b.getColorShade(t,q.options.effects.highlightLuminosity))}if(q.options.tooltips.enabled){s=u.attr("data-index");i.showTooltip(q,s)}var w=u.attr("class")===q.cssPrefix+"expanded";d.onSegmentEvent(q,q.options.callbacks.onMouseoverSegment,u,w)});r.on("mousemove",function(){i.moveTooltip(q)});r.on("mouseout",function(){var v=d3.select(this);var u,t;if(v.attr("class")===q.cssPrefix+"arc"){u=v.select("path")}else{t=v.attr("data-index");u=d3.select("#"+q.cssPrefix+"segment"+t)}if(q.options.effects.highlightSegmentOnMouseover){t=u.attr("data-index");var s=q.options.colors[t];if(q.options.misc.gradient.enabled){s="url(#"+q.cssPrefix+"grad"+t+")"}u.style("fill",s)}if(q.options.tooltips.enabled){t=u.attr("data-index");i.hideTooltip(q,t)}var w=u.attr("class")===q.cssPrefix+"expanded";d.onSegmentEvent(q,q.options.callbacks.onMouseoutSegment,u,w)})},onSegmentEvent:function(q,t,s,u){if(!b.isFunction(t)){return}var r=parseInt(s.attr("data-index"),10);t({segment:s.node(),index:r,expanded:u,data:q.options.data.content[r]})},openSegment:function(q,r){if(q.isOpeningSegment){return}q.isOpeningSegment=true;d.maybeCloseOpenSegment(q);d3.select(r).transition().ease(d.effectMap[q.options.effects.pullOutSegmentOnClick.effect]).duration(q.options.effects.pullOutSegmentOnClick.speed).attr("transform",function(w,u){var A=q.arc.centroid(w),s=A[0],z=A[1],v=Math.sqrt(s*s+z*z),t=parseInt(q.options.effects.pullOutSegmentOnClick.size,10);return"translate("+((s/v)*t)+","+((z/v)*t)+")"}).on("end",function(t,s){q.currentlyOpenSegment=r;q.isOpeningSegment=false;d3.select(r).attr("class",q.cssPrefix+"expanded")})},maybeCloseOpenSegment:function(q){if(d3.selectAll("."+q.cssPrefix+"expanded").size()>0){d.closeSegment(q,d3.select("."+q.cssPrefix+"expanded").node())}},closeSegment:function(q,r){d3.select(r).transition().duration(400).attr("transform","translate(0,0)").on("end",function(t,s){d3.select(r).attr("class","");q.currentlyOpenSegment=null})},getCentroid:function(q){var r=q.getBBox();return{x:r.x+r.width/2,y:r.y+r.height/2}},getSegmentAngle:function(w,t,y,q){var z=k({compounded:true,midpoint:false},q);var s=t[w].value;var v;if(z.compounded){v=0;for(var u=0;u<=w;u++){v+=t[u].value}}if(typeof v==="undefined"){v=s}var r=(v/y)*360;if(z.midpoint){var x=(s/y)*360;r-=(x/2)}return r}};var o={offscreenCoord:-10000,addTitle:function(q){var r=q.svg.selectAll("."+q.cssPrefix+"title").data([q.options.header.title]).enter().append("text").text(function(s){return s.text}).attr("id",q.cssPrefix+"title").attr("class",q.cssPrefix+"title").attr("x",o.offscreenCoord).attr("y",o.offscreenCoord).attr("text-anchor",function(){var s;if(q.options.header.location==="top-center"||q.options.header.location==="pie-center"){s="middle"}else{s="left"}return s}).attr("fill",function(s){return s.color}).style("font-size",function(s){return s.fontSize+"px"}).style("font-family",function(s){return s.font})},positionTitle:function(s){var t=s.textComponents;var z=s.options.header.location;var q=s.options.misc.canvasPadding;var r=s.options.size.canvasWidth;var A=s.options.header.titleSubtitlePadding;var w;if(z==="top-left"){w=q.left}else{w=((r-q.right)/2)+q.left}w+=s.options.misc.pieCenterOffset.x;var v=q.top+t.title.h;if(z==="pie-center"){v=s.pieCenter.y;if(t.subtitle.exists){var u=t.title.h+A+t.subtitle.h;v=v-(u/2)+t.title.h}else{v+=(t.title.h/4)}}s.svg.select("#"+s.cssPrefix+"title").attr("x",w).attr("y",v)},addSubtitle:function(q){var r=q.options.header.location;q.svg.selectAll("."+q.cssPrefix+"subtitle").data([q.options.header.subtitle]).enter().append("text").text(function(s){return s.text}).attr("x",o.offscreenCoord).attr("y",o.offscreenCoord).attr("id",q.cssPrefix+"subtitle").attr("class",q.cssPrefix+"subtitle").attr("text-anchor",function(){var s;if(r==="top-center"||r==="pie-center"){s="middle"}else{s="left"}return s}).attr("fill",function(s){return s.color}).style("font-size",function(s){return s.fontSize+"px"}).style("font-family",function(s){return s.font})},positionSubtitle:function(s){var t=s.options.misc.canvasPadding;var r=s.options.size.canvasWidth;var q;if(s.options.header.location==="top-left"){q=t.left}else{q=((r-t.right)/2)+t.left}q+=s.options.misc.pieCenterOffset.x;var u=o.getHeaderHeight(s);s.svg.select("#"+s.cssPrefix+"subtitle").attr("x",q).attr("y",u)},addFooter:function(q){q.svg.selectAll("."+q.cssPrefix+"footer").data([q.options.footer]).enter().append("text").text(function(r){return r.text}).attr("x",o.offscreenCoord).attr("y",o.offscreenCoord).attr("id",q.cssPrefix+"footer").attr("class",q.cssPrefix+"footer").attr("text-anchor",function(){var r="left";if(q.options.footer.location==="bottom-center"){r="middle"}else{if(q.options.footer.location==="bottom-right"){r="left"}}return r}).attr("fill",function(r){return r.color}).style("font-size",function(r){return r.fontSize+"px"}).style("font-family",function(r){return r.font})},positionFooter:function(t){var w=t.options.footer.location;var s=t.textComponents.footer.w;var r=t.options.size.canvasWidth;var u=t.options.size.canvasHeight;var v=t.options.misc.canvasPadding;var q;if(w==="bottom-left"){q=v.left}else{if(w==="bottom-right"){q=r-s-v.right}else{q=r/2}}t.svg.select("#"+t.cssPrefix+"footer").attr("x",q).attr("y",u-v.bottom)},getHeaderHeight:function(r){var s;if(r.textComponents.title.exists){var q=r.textComponents.title.h+r.options.header.titleSubtitlePadding+r.textComponents.subtitle.h;if(r.options.header.location==="pie-center"){s=r.pieCenter.y-(q/2)+q}else{s=q+r.options.misc.canvasPadding.top}}else{if(r.options.header.location==="pie-center"){var t=r.options.misc.canvasPadding.bottom+r.textComponents.footer.h;s=((r.options.size.canvasHeight-t)/2)+r.options.misc.canvasPadding.top+(r.textComponents.subtitle.h/2)}else{s=r.options.misc.canvasPadding.top+r.textComponents.subtitle.h}}return s}};var i={addTooltips:function(q){var r=q.svg.insert("g").attr("class",q.cssPrefix+"tooltips");r.selectAll("."+q.cssPrefix+"tooltip").data(q.options.data.content).enter().append("g").attr("class",q.cssPrefix+"tooltip").attr("id",function(t,s){return q.cssPrefix+"tooltip"+s}).style("opacity",0).append("rect").attr("rx",q.options.tooltips.styles.borderRadius).attr("ry",q.options.tooltips.styles.borderRadius).attr("x",-q.options.tooltips.styles.padding).attr("opacity",q.options.tooltips.styles.backgroundOpacity).style("fill",q.options.tooltips.styles.backgroundColor);r.selectAll("."+q.cssPrefix+"tooltip").data(q.options.data.content).append("text").attr("fill",function(s){return q.options.tooltips.styles.color}).style("font-size",function(s){return q.options.tooltips.styles.fontSize}).style("font-family",function(s){return q.options.tooltips.styles.font}).text(function(u,t){var s=q.options.tooltips.string;if(q.options.tooltips.type==="caption"){s=u.caption}return i.replacePlaceholders(q,s,t,{label:u.label,value:u.value,percentage:u.percentage})});r.selectAll("."+q.cssPrefix+"tooltip rect").attr("width",function(u,s){var t=b.getDimensions(q.cssPrefix+"tooltip"+s);return t.w+(2*q.options.tooltips.styles.padding)}).attr("height",function(u,s){var t=b.getDimensions(q.cssPrefix+"tooltip"+s);return t.h+(2*q.options.tooltips.styles.padding)}).attr("y",function(u,s){var t=b.getDimensions(q.cssPrefix+"tooltip"+s);return -(t.h/2)+1})},showTooltip:function(q,r){var s=q.options.tooltips.styles.fadeInSpeed;if(i.currentTooltip===r){s=1}i.currentTooltip=r;d3.select("#"+q.cssPrefix+"tooltip"+r).transition().duration(s).style("opacity",function(){return 1});i.moveTooltip(q)},moveTooltip:function(q){d3.selectAll("#"+q.cssPrefix+"tooltip"+i.currentTooltip).attr("transform",function(t){var s=d3.mouse(this.parentNode);var r=s[0]+q.options.tooltips.styles.padding+2;var u=s[1]-(2*q.options.tooltips.styles.padding)-2;return"translate("+r+","+u+")"})},hideTooltip:function(q,r){d3.select("#"+q.cssPrefix+"tooltip"+r).style("opacity",function(){return 0});d3.select("#"+q.cssPrefix+"tooltip"+i.currentTooltip).attr("transform",function(u,t){var s=q.options.size.canvasWidth+1000;var v=q.options.size.canvasHeight+1000;return"translate("+s+","+v+")"})},replacePlaceholders:function(q,u,r,t){if(b.isFunction(q.options.tooltips.placeholderParser)){q.options.tooltips.placeholderParser(r,t)}var s=function(){return function(v){var w=arguments[1];if(t.hasOwnProperty(w)){return t[arguments[1]]}else{return arguments[0]}}};return u.replace(/\{(\w+)\}/g,s(t))}};var c=function(r,q){this.element=r;if(typeof r==="string"){var s=r.replace(/^#/,"");this.element=document.getElementById(s)}var t={};k(true,t,h,q);this.options=t;if(this.options.misc.cssPrefix!==null){this.cssPrefix=this.options.misc.cssPrefix}else{this.cssPrefix="p"+p+"_";p++}if(!m.initialCheck(this)){return}d3.select(this.element).attr(g,f);j.call(this);l.call(this)};c.prototype.recreate=function(){if(!m.initialCheck(this)){return}j.call(this);l.call(this)};c.prototype.redraw=function(){this.element.innerHTML="";l.call(this)};c.prototype.destroy=function(){this.element.innerHTML="";d3.select(this.element).attr(g,null)};c.prototype.getOpenSegment=function(){var r=this.currentlyOpenSegment;if(r!==null&&typeof r!=="undefined"){var q=parseInt(d3.select(r).attr("data-index"),10);return{element:r,index:q,data:this.options.data.content[q]}}else{return null}};c.prototype.openSegment=function(q){q=parseInt(q,10);if(q<0||q>this.options.data.content.length-1){return}d.openSegment(this,d3.select("#"+this.cssPrefix+"segment"+q).node())};c.prototype.closeSegment=function(){d.maybeCloseOpenSegment()};c.prototype.updateProp=function(s,t){switch(s){case"header.title.text":var q=b.processObj(this.options,s);b.processObj(this.options,s,t);d3.select("#"+this.cssPrefix+"title").html(t);if((q===""&&t!=="")||(q!==""&&t==="")){this.redraw()}break;case"header.subtitle.text":var r=b.processObj(this.options,s);b.processObj(this.options,s,t);d3.select("#"+this.cssPrefix+"subtitle").html(t);if((r===""&&t!=="")||(r!==""&&t==="")){this.redraw()}break;case"callbacks.onload":case"callbacks.onMouseoverSegment":case"callbacks.onMouseoutSegment":case"callbacks.onClickSegment":case"effects.pullOutSegmentOnClick.effect":case"effects.pullOutSegmentOnClick.speed":case"effects.pullOutSegmentOnClick.size":case"effects.highlightSegmentOnMouseover":case"effects.highlightLuminosity":b.processObj(this.options,s,t);break;default:b.processObj(this.options,s,t);this.destroy();this.recreate();break}};var j=function(){this.options.data.content=n.sortPieData(this);if(this.options.data.smallSegmentGrouping.enabled){this.options.data.content=b.applySmallSegmentGrouping(this.options.data.content,this.options.data.smallSegmentGrouping)}this.options.colors=b.initSegmentColors(this);this.totalSize=n.getTotalPieSize(this.options.data.content);var t=this.options.labels.percentage.decimalPlaces;for(var s=0;st&&(r-=t)}const i=t(a.size.pieOuterRadius,r);return{outerRadius:i,innerRadius:t(a.size.pieInnerRadius,i)}}(),c=s+a.labels.outer.pieDistance,u=d3.line().curve(d3.curveCatmullRomOpen),f=d3.select("body").append("div").attr("id",t+"-tooltip").attr("class","d3pie-tooltip"),p=f.append("span").attr("id",t+"-tooltip-text"),g=n.append("defs");this.data=function(e){let n=$.extend(!0,[],e);const l=[],h=n.reduce(function(t,e){return t+(e.value||0)},0);f.datum({total:h}),n.unshift({label:"undefined",color:a.gradient.enabled?"steelblue":"#ecf1f5",value:0===h?1:0});const b=d3.scaleOrdinal(d3.schemeSet1);function v(t,e){return void 0!==t&&void 0!==t.color?t.color:b(e)}function A(t,e,a=e){return d3.arc().innerRadius(e).outerRadius(a).centroid(t)}function x(t){return d3.interpolate(i[t.data.label],t)}function m(t){const e=c-.1;return Math.max(-e,Math.min(e,t))}const y=d3.transition().duration(a.duration);if(a.gradient.enabled){const e=g.selectAll("radialGradient").data(n,function(t){return t.label}).enter().append("radialGradient").attr("gradientUnits","userSpaceOnUse").attr("cx",0).attr("cy",0).attr("r","120%").attr("id",function(e,a){return t+"-grad"+a});e.append("stop").attr("class","grad-stop-0").style("stop-color",function(t,e){return v(t,e)}),e.append("stop").attr("class","grad-stop-1").attr("offset",a.gradient.percentage+"%"),g.selectAll("radialGradient").select(".grad-stop-0").transition(y).style("stop-color",function(t,e){return v(t,e)})}function M(t){return t.data.label}const R=d3.pie().sort(null).value(function(t){return t.value}),w=r.selectAll(".slice-g").data(R(n),M),P=w.enter().append("g").attr("class","slice-g").on("mouseover",function(t){const e=f.datum().total,a=e?Math.round(100*t.data.value/e):NaN;t.data.value?(f.transition().duration(300).style("opacity",1),p.text(t.data.label+(e?": "+t.data.value+" ("+a+"%)":""))):f.transition().duration(300).style("opacity",0),f.each(function(t){t.height=this.getBoundingClientRect().height})}).on("mouseout",function(){f.transition().duration(300).style("opacity",0)}).on("mousemove",function(){const{pageX:t,pageY:e}=d3.event;f.style("left",t+"px").style("top",function(t){return e-t.height-2+"px"})});if(P.append("path").attr("id",function(e,a){return t+"-slice"+a}).attr("class","slice").attr("fill",function(e,n){return a.gradient.enabled?"url(#"+t+"-grad"+n+")":v(e.data,n)}),w.exit().each(function(t,e){n[e]={value:0,label:t.data.label}}),R(n).forEach(function(t,e){if(void 0===i[t.data.label]){const a=e?i[R(n)[e-1].data.label].endAngle:0;i[t.data.label]={startAngle:a,endAngle:a}}}),r.selectAll(".slice").data(R(n),M).transition(y).attrTween("d",function(t){return function(e){return d3.arc().padAngle(a.padAngle).cornerRadius(a.cornerRadius).innerRadius(d).outerRadius(s)(x(t)(e))}}).end().then(function(){n=n.filter(function(t,e){return 0===e||t.value}),g.selectAll("radialGradient").data(n,function(t){return t.label}).exit().remove(),r.selectAll(".slice-g").data(R(n),M).exit().each(function(t){delete i[t.data.label],delete o[t.data.label]}).remove();for(const t of R(n))i[t.data.label]=t,"none"!==a.labels.outer.format&&(o[t.data.label].currentAngle=o[t.data.label].newAngle)}).catch(function(t){console.warn(t)}),P.append("text").attr("class","inner-label").attr("dy",".35em"),r.selectAll(".inner-label").data(R(n),M).text(function(t){return"undefined"===t.data.label?"undefined":Math.round(100*t.data.value/h)+"%"}).transition(y).attrTween("opacity",function(t){return t.data.value?function(e){const n=x(t)(e);return 100*(n.endAngle-n.startAngle)/(2*Math.PI)=0?a.labels.outer.collideHeight:-a.labels.outer.collideHeight),l.push({fx:r,y:d})}),d3.forceSimulation(l).alphaMin(.5).force("collide",d3.forceCollide(a.labels.outer.collideHeight/2)).force("boundY",function(){for(const t of l)t.y=m(t.y)}).tick(30);const t=P.append("g").attr("class","outer-label-g");t.append("text").attr("class","outer-label").attr("dy",".35em").text(M),t.append("path").attr("class","link"),r.selectAll(".outer-label-g").data(R(n),M).transition(y).style("opacity",function(t,e){return e&&t.value?1:0}).each(function(t,e){$(this).children(".link").attr("stroke",v(t.data,e))}),r.selectAll(".outer-label").data(R(n),M).transition(y).attrTween("transform",function(t,e){o[t.data.label].newAngle=function(){const a=m(l[e].y);let n=Math.sqrt(Math.pow(c,2)-Math.pow(a,2));(t.endAngle+t.startAngle)/2>Math.PI&&(n*=-1);let r=Math.PI/2-Math.atan2(-a,n);return r<0&&(r+=2*Math.PI),{startAngle:r,endAngle:r}}();const a=d3.interpolate(o[t.data.label].currentAngle,o[t.data.label].newAngle);return function(n){const l=A(a(n),c),[i,o]=l,d=i>0?{dx:5,textAnchor:"start"}:{dx:-5,textAnchor:"end"};return d3.select(r.selectAll(".link").nodes()[e]).datum([A(x(t)(n),s),A(x(t)(n),s+5),[i,o],[i+d.dx,o]]).attr("d",u),d3.select(r.selectAll(".outer-label").nodes()[e]).attr("dx",d.dx).style("text-anchor",d.textAnchor),"translate("+l+")"}})}}} \ No newline at end of file diff --git a/interface/js/main.js b/interface/js/main.js index 7d5c5e783..3c45003b4 100644 --- a/interface/js/main.js +++ b/interface/js/main.js @@ -23,7 +23,7 @@ requirejs.config({ codejar: {exports: "CodeJar", deps:["linenumbers"]}, bootstrap: {exports:"bootstrap", deps:["jquery"]}, d3evolution: {exports:"D3Evolution", deps:["d3", "jquery"]}, - d3pie: {exports:"d3pie", deps:["d3.global", "jquery"]}, + d3pie: {exports:"D3Pie", deps:["d3.global", "jquery"]}, fontawesome: {exports: "FontAwesome", deps:["fontawesome_solid"]}, footable: {deps:["bootstrap", "jquery"]}, linenumbers: {exports: "withLineNumbers", deps:["prism"]}, -- cgit v1.2.3