I use D3 to draw everything on the screen, the problem is that i want all the elements to fit in the block, while leaving as little free space as possible, how to do this, size can take a value from 1 to infinity. At the same time, it is necessary to preserve their ratio between themselves, how to do this is clear, but the question is how to calculate the multiplier that will allow them all to fit into the given block sizes.
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-cloud/build/d3.layout.cloud.min.js"></script>
const width = 800;
const height = 600;
const svg = d3
.select("#tagCloud")
.append("svg")
.attr("width", width)
.attr("height", height);
const layout = d3.layout.cloud()
.size([width, height])
.words(tags.map(tag => ({ text: tag.text, size: tag.size, url: tag.url })))
.padding(5)
.rotate(() => ~~(Math.random() * 2) * 90)
.font("Impact")
.fontSize(x => x.size)
.on("end", draw);
layout.start();
function draw(words) {
svg.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`)
.selectAll("text")
.data(words)
.enter()
.append("text")
.style("font-size", x => `${x.size}px`)
.style("font-family", "Impact")
.style("fill", () => d3.schemeCategory10[Math.floor(Math.random() * 10)])
.attr("text-anchor", "middle")
.attr("transform", x => `translate(${x.x}, ${x.y}) rotate(${x.rotate})`)
.text(x => x.text)
.on("click", function (item, index) {
if (item.url) {
window.location.href = item.url;
}
});
}