From 8bb998f26c9a5ef9bf0579106cad45e39e26cc4a Mon Sep 17 00:00:00 2001 From: moisseev Date: Wed, 7 Sep 2022 14:58:50 +0300 Subject: [PATCH] [WebUI] Put total in the center of pie charts --- interface/css/d3pie.css | 8 ++++++++ interface/css/rspamd.css | 3 --- interface/js/app/graph.js | 9 +++++++-- interface/js/app/stats.js | 12 +++++++++++- interface/js/lib/d3pie.min.js | 4 ++-- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/interface/css/d3pie.css b/interface/css/d3pie.css index 71419a3d6..813ce9fe5 100644 --- a/interface/css/d3pie.css +++ b/interface/css/d3pie.css @@ -14,6 +14,14 @@ line-height: normal; } +.d3pie .total-text { + text-anchor: middle; + dominant-baseline: central; +} +.d3pie .total-value { + font-family: Arial, sans-serif; +} + .d3pie .inner-label { fill: #eeeeee; pointer-events: none; diff --git a/interface/css/rspamd.css b/interface/css/rspamd.css index 044bdd645..11e0819e2 100644 --- a/interface/css/rspamd.css +++ b/interface/css/rspamd.css @@ -345,9 +345,6 @@ table#symbolsTable input[type="number"] { text-align: left; font-size: 12px; } -#rrd-pie { - font-size: 10px; -} /* Throughput graph controls */ #graph_controls select { diff --git a/interface/js/app/graph.js b/interface/js/app/graph.js index 6bd83c72b..3e4983a71 100644 --- a/interface/js/app/graph.js +++ b/interface/js/app/graph.js @@ -34,6 +34,7 @@ define(["jquery", "d3evolution", "d3pie", "footable"], size: { canvasWidth: 400, canvasHeight: 180, + pieInnerRadius: "50%", pieOuterRadius: "80%" }, labels: { @@ -41,14 +42,18 @@ define(["jquery", "d3evolution", "d3pie", "footable"], format: "none" }, inner: { - hideWhenLessThanPercentage: 8 + hideWhenLessThanPercentage: 8, + offset: 0 }, }, padAngle: 0.02, pieCenterOffset: { x: -120, y: 10, - } + }, + total: { + enabled: true + }, }; var ui = {}; diff --git a/interface/js/app/stats.js b/interface/js/app/stats.js index 8b38d7f10..7ce239ef9 100644 --- a/interface/js/app/stats.js +++ b/interface/js/app/stats.js @@ -226,11 +226,21 @@ define(["jquery", "d3pie"], if (!graphs.chart) { graphs.chart = new D3Pie("chart", { labels: { + inner: { + offset: 0 + }, outer: { collideHeight: 18, } }, - title: "Rspamd filter stats" + size: { + pieInnerRadius: "50%" + }, + title: "Rspamd filter stats", + total: { + enabled: true, + label: "Scanned" + } }); } diff --git a/interface/js/lib/d3pie.min.js b/interface/js/lib/d3pie.min.js index f4a29c540..823f69735 100644 --- a/interface/js/lib/d3pie.min.js +++ b/interface/js/lib/d3pie.min.js @@ -1,5 +1,5 @@ /*! - * rspamd-D3Pie 1.0.0 (https://github.com/moisseev/rspamd-D3Pie) + * rspamd-D3Pie 1.1.0 (https://github.com/moisseev/rspamd-D3Pie) * Copyright (c) 2022, Alexander Moisseev, BSD 2-Clause */ -function D3Pie(v,t){"use strict";const A=$.extend(!0,{canvasPadding:5,cornerRadius:3,duration:1250,gradient:{enabled:!0,percentage:100},labels:{inner:{hideWhenLessThanPercentage:4,offset:.15},outer:{collideHeight:13,format:"label",pieDistance:30}},padAngle:.01,pieCenterOffset:{x:0,y:0},size:{canvasHeight:400,canvasWidth:600,pieInnerRadius:"20%",pieOuterRadius:"85%"},title:""},t),e=(this.destroy=function(){d3.selectAll("#"+v+" svg, #"+v+"-tooltip").remove()},this.destroy(),d3.select("#"+v).append("svg").attr("class","d3pie").attr("width",A.size.canvasWidth).attr("height",A.size.canvasHeight));let l=0;if(""!==A.title){const a=e.append("svg:text").attr("class","chart-title").attr("x",A.size.canvasWidth/2);a.append("tspan").text(A.title+" "),l=a.node().getBBox().height,a.attr("y",l+A.canvasPadding)}const x=e.append("g").attr("transform","translate("+(A.size.canvasWidth/2+A.pieCenterOffset.x)+","+(A.size.canvasHeight/2+l/2+A.pieCenterOffset.y)+")"),m={},y={},{outerRadius:M,innerRadius:R}=function(){function t(t,e){var a;return/%/u.test(t)?(a=Math.max(0,Math.min(99,parseInt(t.replace(/[\D]/u,""),10)))/100,Math.floor(e*a)):parseInt(t,10)}var e=A.size.canvasWidth-2*A.canvasPadding,a=A.size.canvasHeight-2*A.canvasPadding-l;let n=Math.min(e,a)/2;"none"!==A.labels.outer.format&&(e=parseInt(A.labels.outer.pieDistance,10),n>e&&(n-=e));a=t(A.size.pieOuterRadius,n);return{outerRadius:a,innerRadius:t(A.size.pieInnerRadius,a)}}(),w=M+A.labels.outer.pieDistance,P=d3.line().curve(d3.curveCatmullRomOpen),z=d3.select("body").append("div").attr("id",v+"-tooltip").attr("class","d3pie-tooltip"),I=z.append("span").attr("id",v+"-tooltip-text"),H=e.append("defs");this.data=function(t){let l=$.extend(!0,[],t);const o=[],e=l.reduce(function(t,e){return t+(e.value||0)},0),a=(z.datum({total:e}),l.unshift({label:"undefined",color:A.gradient.enabled?"steelblue":"#ecf1f5",value:0===e?1:0}),d3.scaleOrdinal(d3.schemeSet1));function n(t,e){return void 0!==t&&void 0!==t.color?t.color:a(e)}function s(t,e,a=e){return d3.arc().innerRadius(e).outerRadius(a).centroid(t)}function c(t){return d3.interpolate(m[t.data.label],t)}function u(t){var e=w-.1;return Math.max(-e,Math.min(e,t))}function r(r,i){y[r.data.label].newAngle=function(){var t=u(o[i].y);let e=Math.sqrt(Math.pow(w,2)-Math.pow(t,2)),a=((r.endAngle+r.startAngle)/2>Math.PI&&(e*=-1),Math.PI/2-Math.atan2(-t,e));return a<0&&(a+=2*Math.PI),{startAngle:a,endAngle:a}}();const d=d3.interpolate(y[r.data.label].currentAngle,y[r.data.label].newAngle);return function(t){var e=s(d(t),w),[a,n]=e,l=0{const{pageX:e,pageY:a}=t;z.style("left",e+"px").style("top",function(t){return a-t.height-2+"px"})});if(p.append("path").attr("id",function(t,e){return v+"-slice"+e}).attr("class","slice").attr("fill",function(t,e){return A.gradient.enabled?"url(#"+v+"-grad"+e+")":n(t.data,e)}),f.exit().each(function(t,e){l[e]={value:0,label:t.data.label}}),d(l).forEach(function(t,e){void 0===m[t.data.label]&&(e=e?m[d(l)[e-1].data.label].endAngle:0,m[t.data.label]={startAngle:e,endAngle:e})}),x.selectAll(".slice").data(d(l),i).transition(t).attrTween("d",function(e){return function(t){return d3.arc().padAngle(A.padAngle).cornerRadius(A.cornerRadius).innerRadius(R).outerRadius(M)(c(e)(t))}}).end().then(function(){l=l.filter(function(t,e){return 0===e||t.value}),H.selectAll("radialGradient").data(l,function(t){return t.label}).exit().remove(),x.selectAll(".slice-g").data(d(l),i).exit().each(function(t){delete m[t.data.label],delete y[t.data.label]}).remove();for(const t of d(l))m[t.data.label]=t,"none"!==A.labels.outer.format&&(y[t.data.label].currentAngle=y[t.data.label].newAngle)}).catch(function(t){console.warn(t)}),p.append("text").attr("class","inner-label").attr("dy",".35em"),x.selectAll(".inner-label").data(d(l),i).text(function(t){return"undefined"===t.data.label?"undefined":Math.round(100*t.data.value/e)+"%"}).transition(t).attrTween("opacity",function(e){return e.data.value?function(t){t=c(e)(t);return 100*(t.endAngle-t.startAngle)/(2*Math.PI)e&&(n-=e));a=t(A.size.pieOuterRadius,n);return{outerRadius:a,innerRadius:t(A.size.pieInnerRadius,a)}}(),w=M+A.labels.outer.pieDistance,z=d3.line().curve(d3.curveCatmullRomOpen),P=d3.select("body").append("div").attr("id",v+"-tooltip").attr("class","d3pie-tooltip"),r=P.append("span").attr("id",v+"-tooltip-text");function I(t){t.on("mouseover",function(t,e){var a=P.datum().total,n=a?Math.round(100*e.data.value/a):NaN;e.data.value?(P.transition().duration(300).style("opacity",1),r.text(e.data.label+(a?": "+e.data.value+" ("+n+"%)":""))):P.transition().duration(300).style("opacity",0),P.each(function(t){t.height=this.getBoundingClientRect().height})}).on("mouseout",function(){P.transition().duration(300).style("opacity",0)}).on("mousemove",t=>{const{pageX:e,pageY:a}=t;P.style("left",e+"px").style("top",function(t){return a-t.height-2+"px"})})}const H=x.append("g");if(I(H),H.append("circle").attr("r",R).style("opacity",0),A.total.enabled){const n=H.append("text").attr("class","total-text");n.append("tspan").attr("class","total-value").style("font-size",.6*R+"px"),n.append("tspan").attr("x","0").attr("dy",.5*R).text(void 0!==A.total.label?A.total.label:"Total")}const O=e.append("defs");this.data=function(t){let l=$.extend(!0,[],t);const d=[],e=l.reduce(function(t,e){return t+(e.value||0)},0),a=(P.datum({total:e}),H.datum({data:{label:void 0!==A.total.label?A.total.label:"Total",value:e}}),A.total.enabled&&H.select(".total-value").text(d3.format(".3~s")(e)),l.unshift({label:"undefined",color:A.gradient.enabled?"steelblue":"#ecf1f5",value:0===e?1:0}),d3.scaleOrdinal(d3.schemeSet1));function n(t,e){return void 0!==t&&void 0!==t.color?t.color:a(e)}function s(t,e,a=e){return d3.arc().innerRadius(e).outerRadius(a).centroid(t)}function c(t){return d3.interpolate(y[t.data.label],t)}function u(t){var e=w-.1;return Math.max(-e,Math.min(e,t))}function r(r,i){m[r.data.label].newAngle=function(){var t=u(d[i].y);let e=Math.sqrt(Math.pow(w,2)-Math.pow(t,2)),a=((r.endAngle+r.startAngle)/2>Math.PI&&(e*=-1),Math.PI/2-Math.atan2(-t,e));return a<0&&(a+=2*Math.PI),{startAngle:a,endAngle:a}}();const o=d3.interpolate(m[r.data.label].currentAngle,m[r.data.label].newAngle);return function(t){var e=s(o(t),w),[a,n]=e,l=0