shape_ball = {
const ball = function(conf){
const obj = {}
const _config = conf ? conf:{value:20, max:100, min:0, color:"#717e29", width:300, height:200, depth:100} ;
d3.select('body').append("svg").node().innerHTML = `<defs>
<filter id="filter1">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blurOut" />
<!-- We cut off the parts that overlap the source graphic… -->
<feComposite operator="in" in="blurOut" in2="SourceAlpha" result="COMPOSITE"/>
<!-- … and then merge source graphic and lighting effect: -->
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode in="COMPOSITE"/>
</feMerge>
</filter>
<!-- https://www.smashingmagazine.com/2015/05/why-the-svg-filter-is-awesome/ -->
<filter id="Steelfilter">
<!--We create a heightmap by blurring the source: -->
<feGaussianBlur stdDeviation="10" in="SourceAlpha" result="BLUR"/>
<!-- We then define a lighting effect with a point light that is positioned at virtual 3D coordinates x: 40px, y: -30px, z: 200px: -->
<feSpecularLighting surfaceScale="6" specularConstant="1" specularExponent="20" lighting-color="#ffffff" in="BLUR" result="SPECULAR">
<fePointLight x="40" y="40" z="2000" />
</feSpecularLighting>
<!-- We cut off the parts that overlap the source graphic… -->
<feComposite operator="in" in="SPECULAR" in2="SourceAlpha" result="COMPOSITE"/>
<!-- … and then merge source graphic and lighting effect: -->
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode in="COMPOSITE"/>
</feMerge>
</filter>
</defs>` ;
obj.updateShape = function(node,config){
d3.select(node).selectAll("*").remove();
this.render(node,config) ;
};
obj.updateValue = function(node,v){
node.value = v;
let conf = node.config ;
let ballsGroup = d3.select(node).selectAll("circle")
.attr("r",d=>d.value);
};
obj.render = function(node,config){
config = Object.assign({},_config,config);
node.config = config;
//All of the "official" planets in our Solar System
var planets = [
{planet: "Mercury", diameter: 0.383, color: "#A17F5D"},
{planet: "Venus", diameter: 0.949, color: "#E89624"},
{planet: "Earth", diameter: 1, color: "#518E87"},
{planet: "Mars", diameter: 0.532, color: "#964120"},
{planet: "Jupiter", diameter: 11.21, color: "#F8800F"},
{planet: "Saturn", diameter: 9.45, color: "#E0B463"},
{planet: "Uranus", diameter: 4.01, color: "#D1E3F4"},
{planet: "Neptune", diameter: 3.88, color: "#515CA8"}
];
let ballsGroup = d3.select(node)
.attr("transform","translate("+[config.x,config.y]+")")
.append("g")
.attr("class","balls");
//Create a radial gradient for each of the planets
var planetGradients = ballsGroup.append("defs").selectAll("radialGradient")
.data(planets)
.enter().append("radialGradient")
//Create a unique id per "planet"
.attr("id", function(d){ return "gradient-" + d.planet; })
.attr("cx", "35%") //Move the x-center location towards the left
.attr("cy", "35%") //Move the y-center location towards the top
.attr("r", "60%"); //Increase the size of the "spread" of the gradient
//Add colors to the gradient
//First a lighter color in the center
planetGradients.append("stop")
.attr("offset", "0%")
.attr("stop-color", function(d) {
return d3.rgb(d.color).brighter(1);
});
//Then the actual color almost halfway
planetGradients.append("stop")
.attr("offset", "50%")
.attr("stop-color", function(d) {
return d.color;
});
//Finally a darker color at the outside
planetGradients.append("stop")
.attr("offset", "100%")
.attr("stop-color", function(d) {
return d3.rgb(d.color).darker(1.75);
});
//Apply to a circle by referencing its unique id in the fill
ballsGroup.selectAll("circle")
.data([config])
.enter()
.append("circle")
.attr("r", 0)
.style("fill", "url(#gradient-Venus)");
ballsGroup.selectAll("path")
.data([{d:"M-40,100 h150 a20,20 0 0,0 20,-20 v-150"}])
.enter()
.append("path")
.attr("d", d=>d.d)
.attr("fill","none")
.attr("filter","url(#Steelfilter)")
.attr("stroke","black")
.attr("stroke-width",20);
this.updateValue(node,config.value);
};
return obj;
}
return ball;
}