Consider the code for some text I'm putting in some circles:
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 1080;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+")");
//var tsvData = d3.tsv('circle-pack-data.tsv');
//tsvData.then(function(rawData) {
/*
var data = rawData.map(function(d) {
return {id:d.id, parentId:d.parentId, size:+d.size}
});
*/
var data = [
[
{'id':'3Q18'},
{'id':'Greater China','parentId':'3Q18','size':428.7,'sign':'negative'},
{'id':'Thematic','parentId':'3Q18', 'size':111.8,'sign':'positive'},
{'id':'US','parentId':'3Q18', 'size':418.3,'sign':'positive'},
{'id':'India','parentId':'3Q18', 'size':9.39,'sign':'negative'},
{'id':'Europe','parentId':'3Q18', 'size':94.0,'sign':'positive'},
{'id':'Japan','parentId':'3Q18', 'size':0,'sign':'positive'},
{'id':'Global','parentId':'3Q18', 'size':41.9,'sign':'negative'}
],
[
{'id':'4Q18'},
{'id':'Greater China','parentId':'4Q18','size':217.8,'sign':'negative'},
{'id':'Thematic','parentId':'4Q18', 'size':100.5,'sign':'positive'},
{'id':'US','parentId':'4Q18', 'size':127.9,'sign':'negative'},
{'id':'India','parentId':'4Q18', 'size':1.5,'sign':'negative'},
{'id':'Europe','parentId':'4Q18', 'size':1.5,'sign':'positive'},
{'id':'Japan','parentId':'4Q18', 'size':0,'sign':'positive'},
{'id':'Global','parentId':'4Q18', 'size':52.8,'sign':'negative'}
],
];
var colorMap = {
'3Q18':"#d9d9d9",
'4Q18':"#d9d9d9",
'3Q19':"#d9d9d9",
'4Q19':"#d9d9d9",
'Greater China':"#003366",
'Thematic':"#366092",
'US':"#4f81b9",
'India':"#95b3d7",
'Europe':"#b8cce4",
'Japan':"#e7eef8",
'Global':"#a6a6a6"
};
var defs = svg.append('svg:defs');
var blue1x = "Fills/blue-1-crosshatch-redo.svg";
var blue2x = "Fills/blue-2-crosshatch.svg";
var blue3x = "Fills/blue-3-crosshatch.svg";
var blue4x = "Fills/blue-4-crosshatch.svg";
var blue5x = "Fills/blue-5-crosshatch.svg";
var blue6x = "Fills/blue-6-crosshatch.svg";
var grayx = "Fills/gray-2-crosshatch.svg";
defs.append("svg:pattern")
.attr("id", "blue1_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue1x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue2_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue2x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue3_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue3x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue4_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue4x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue5_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue5x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "blue6_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", blue6x)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
defs.append("svg:pattern")
.attr("id", "gray_hatch")
.attr("width", 20)
.attr("height", 20)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", grayx)
.attr("width", 20)
.attr("height", 20)
.attr("x", 0)
.attr("y", 0);
var negativeMap = {
'3Q18':"#d9d9d9",
'4Q18':"#d9d9d9",
'3Q19':"#d9d9d9",
'4Q19':"#d9d9d9",
'Greater China':"url(#blue1_hatch)",
'Thematic':"url(#blue2_hatch)",
'US':"url(#blue3_hatch)",
'India':"url(#blue4_hatch)",
'Europe':"url(#blue5_hatch)",
'Japan':"url(#blue6_hatch)",
'Global':"url(#gray_hatch)"
};
var strokeMap = {
"Greater China":"#fff",
"Thematic":"#fff",
"US":"#fff",
'India':"#000",
'Europe':"#000",
'Japan':"#000",
'Global':"#000"
};
for (var j=0; j <(data.length); j++) {
var vData = d3.stratify()(data[j]);
var vLayout = d3.pack().size([250, 250]);
var vRoot = d3.hierarchy(vData).sum(function (d) { return d.data.size; });
var vNodes = vRoot.descendants();
vLayout(vRoot);
var thisClass = "circ"+String(j);
var vSlices = graphGroup.selectAll('.'+thisClass).data(vNodes).attr('class',thisClass).enter().append('g');
console.log(vNodes)
vSlices.append('circle')
.attr('cx', function(d, i) {
return d.x+(j*300)
})
.attr('cy', function (d) { return d.y; })
.attr('r', function (d) { return d.r; })
.style('fill', function(d) {
//console.log(d.data.id)
if (d.data.data.sign=='positive') {
return colorMap[d.data.id];
} else {
return negativeMap[d.data.id];
}
});
vSlices.append('text')
.attr('x', function(d,i) {return d.x+(j*300)})
.attr('y', function(d) {return d.y+5})
.attr('text-anchor','middle')
.style('fill', function(d) {return strokeMap[d.data.id]})
.style('background-color', function(d) {return colorMap[d.data.id]})
.text(function(d) {return d.data.data.size ? d.data.data.size : null});
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Since the fill of the circle can sometimes be a crosshatch (not a solid color), the readability of the text takes a hit. I also found that simply adding a text shadow wasn't quite enough. I'd like to go for the "nuclear" option and assign a solid background color to the text I append. I thought I could do that with the following:
vSlices.append('text')
.attr('x', function(d,i) {return d.x+(j*300)})
.attr('y', function(d) {return d.y+5})
.attr('text-anchor','middle')
.style('fill', function(d) {return strokeMap[d.data.id]})
.style('background-color', function(d) {return colorMap[d.data.id]})
.text(function(d) {return d.data.data.size ? d.data.data.size : null});
However this achieved nothing.
Question
What is the correct way to assign background color for svg text dynamically? (seeing as the background color will need to match the circle's color as per colorMap
)