Using the @mplungjan idea with some code:
Html:
<svg id="svg0" viewBox="0 0 250 250"></svg>
<input style="font-size:100px" type="textbox" id="tbName"></input>
<button style="font-size:100px" onclick=add()>Insert</button>
Javascript:
const startFontSize=30;
const minFontSize=1;
const fontSizeUnit="px";
const fontName="courier";
const fontStyle="";
var startRadius=100;//biggest circle radius
const rate=7/9;//font-size decreasing rate
gap=-2;//space between circles
let names=[['Mary','John','Paul','Lisa','Richard','Steve'],['Cristhian','Alex']];
const tsvg="http://www.w3.org/2000/svg";
const txlink='http://www.w3.org/1999/xlink';
const circlePath="M0 100 C 6 -33 194 -33 200 100 C 194 233 6 233 0 100 Z";//circle of radius 100 centered at (100,100)
function buildFontString(fontSize){
return fontStyle+ ' ' +fontSize +fontSizeUnit+' '+fontName; //font string
}
function calcStringHeight(fontString) {
let text = document.createElementNS(tsvg,"text");
text.style.setProperty("font", fontString);
text.textContent = "AAA";
document.getElementById("svg0").appendChild(text);
let bb=text.getBBox();
document.getElementById("svg0").removeChild(text);
return bb.height;
}
function calcStringWidth(str, fontString) {
let text = document.createElementNS(tsvg,"text");
text.style.setProperty("font", fontString);
text.textContent = str;
document.getElementById("svg0").appendChild(text);
let bb=text.getBBox();
document.getElementById("svg0").removeChild(text);
return bb.width;
}
const pad=calcStringHeight(buildFontString(startFontSize));//space required by text outside circle
//calcs all possible circle radius
function calcRadius(){
let radius=[];
let fontSize=startFontSize;
let currRadius=startRadius;
while(fontSize>minFontSize&&currRadius>gap) {
radius.push(currRadius);
fontSize*=rate;
currRadius-=calcStringHeight(buildFontString(fontSize))+gap;
}
return radius;
}
const radius=calcRadius();
//draw one text circle
function drawTextCircle(str,index){
const scale=startRadius/radius[index];
const fontSize=startFontSize*Math.pow(rate,index);
const path=document.createElementNS(tsvg,"path");
path.id="circle"+index;
path.setAttribute("fill","white");
path.setAttribute("d",circlePath);
path.setAttribute("transform",`translate(${pad+radius[index]*(scale-1)},${pad+radius[index]*(scale-1)}),scale(${1/scale})`);
document.getElementById("svg0").appendChild(path);
const text=document.createElementNS(tsvg,"text");
text.style.setProperty("font", buildFontString(fontSize));
const textPath=document.createElementNS(tsvg,"textPath");
textPath.id="tp"+index;
textPath.setAttributeNS(txlink,"xlink:href","#circle"+index);
textPath.setAttribute("textLength",2*Math.PI*radius[index]-calcStringWidth(" ",buildFontString(fontSize)));
textPath.textContent=str;
text.appendChild(textPath);
document.getElementById("svg0").appendChild(text);
}
function insertName(name){
const len=names.length;
const maxCircles=radius.length;
const currRadius=radius[len-1];
const fontSize=startFontSize*Math.pow(rate,len-1);
let str="",strWidth=0;
//try to add in the current circle
if(len>0){//one circle already exist
for(var i=0;i<names[len-1].length;i++)
str+=names[len-1][i]+" ";
str+=name;
strWidth=calcStringWidth(str,buildFontString(fontSize));
if(strWidth<=2*Math.PI*currRadius)
names[len-1].push(name);//add to the last
else if(len<maxCircles)
names.push([name]);//create new circle
else return false;
}
else if(len<maxCircles)
names.push([name]);//create new circle
else return false;
return true;
}
function drawNames(){
let str="";
for(var i=0;i<names.length;i++){
str="";
for(var j=0;j<names[i].length;j++)
str+=names[i][j]+" ";
drawTextCircle(str,i);
}
}
function drawName(name){
const tp=document.getElementById("tp"+(names.length-1));
if(tp){
const clone=tp.cloneNode(true);
clone.textContent+=name+" ";
tp.parentNode.replaceChild(clone,tp);
}
else
drawTextCircle(name+" ",names.length-1);
}
function add(){
const name=document.getElementById("tbName").value;
if (insertName(name))
drawName(name);
}
drawNames();
One thing that I dont understand is why the space between circles are greater than the calculated font-height... Thanks to SVG, Text does not render on textPath when I create it dynamically
More information in textPath
could be found in
https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/textPath