pointgauge = conf => {
const gauge = {};
const _f1 = d3.format(".1f");
const _config = conf ? conf : {min:0, max:100, radius:40, segments:15, x:0, y:0}
function translateAlong(path,from,to,f,scale) {
var l = to - from;
return function(d, i, a) {
return function(t) {
var x = from + t * l ;
var p = path.getPointAtLength( scale(x) );
if( typeof f === "function" ){
return f(x,p) ;
}
};
};
}
gauge.updateShape = function(node,config){
config = Object.assign({},_config,config);
d3.select(node).selectAll("*").remove();
gauge.render(node,config) ;
}
gauge.updateValue = function(node,value){
let from = node.prevalue ? node.prevalue : 0, to = value;
node.prevalue = value ;
let g = d3.select(node);
//g.select("circle.curpoint").attr("cx",position.x).attr("cy",position.y) ;
// animate
var curvalue = g.select("text.curvalue"), curpoint = g.select("circle.curpoint") ;
g
.transition()
.duration(2000)
.tween("text",translateAlong(node.pnode,from,to,function(x,p){
curvalue.text(_f1(x)) ;
curpoint.attr("cx",p.x).attr("cy",p.y) ;}, node.scale));
}
gauge.render = function(node,config){
//console.log("render:"+ node);
config = Object.assign({},_config,config);
let g=d3.select(node)
.attr("transform","translate("+[config.x,config.y]+")") ;
let path = d3.path();
let tpath = d3.path();
let startAngle=-Math.PI-1, endAngle=0+1
path.arc(0,0,config.radius,startAngle,endAngle);
tpath.arc(0,0,config.radius+15,startAngle,endAngle);
let p = g.append("path")
.attr("d", path.toString() )
.attr("stroke","#333")
.attr("stroke-width", 0)
.attr("fill","none");
node.pnode = p.node();
let t = g.append("path")
.attr("d", tpath.toString() )
.attr("stroke","#333")
.attr("stroke-width", 0)
.attr("fill","none");
node.tnode = t.node();
//def scale function
let segmentScale = d3.scaleLinear().domain([0, config.segments]).range([0, node.pnode.getTotalLength()]);
let txtScale = d3.scaleLinear().domain([0, config.segments]).range([0, node.tnode.getTotalLength()]);
let scale = d3.scaleLinear().domain([config.min, config.max]).range([0, node.pnode.getTotalLength()]);
node.scale =scale ;
//generate background points
let bkPoints = [] ;
let bkTxt = [];
for(let i=0 ; i<=config.segments; i++){
let len = segmentScale(i) ;
let point = node.pnode.getPointAtLength(len);
let v = scale.invert(len) ;
point.r = 3;
bkPoints.push( point ) ;
if( v === parseInt(v,10) ) {
point.r = 6;
let tpoint = node.tnode.getPointAtLength( txtScale(i) );
tpoint.y = tpoint.y + 3;
tpoint.text = v ;
bkTxt.push( tpoint );
}
}
g.selectAll(".bkpoint")
.data(bkPoints)
.enter()
.append("circle")
.attr("class","bkpoint")
.attr("cx", d=>{return d.x} )
.attr("cy", d=>{return d.y} )
.attr("r", d=>{return d.r} )
.attr("fill","#5c6d76");
g.selectAll(".bktxt")
.data(bkTxt)
.enter()
.append("text")
.attr("class","bktxt unselectable")
.attr("x", d=>{return d.x} )
.attr("y", d=>{return d.y} )
.attr("text-anchor", "middle")
.attr("fill","#5c6d76")
.style("font-size", "10px")
.text( d=>{return d.text} );
// current value and point
g.append("circle").attr("class","curpoint").attr("r",5).attr("fill","#ff9633");
g.append("text")
.attr("class","curvalue unselectable")
.attr("y",10)
.attr("text-anchor", "middle")
.attr("fill","#CCC")
.style("font-size", "28px");
gauge.updateValue(node, config.value) ;
}
return gauge;
}