Harel.Lebel
Harel.Lebel

Reputation: 289

D3 word-cloud: how to auto size the font so words will not run out , and to scale words to all the screen?

I'm using Jason Davies d3-cloud.js to implement my word cloud, here

1.The words are running out whenever the initial window size too small. so for that I have function that calculate the pixels needed to the words size, but I'm using if else condition which is not always efficient:

_.forEach(data, function (word) {
  pixNeeded += that.wordService.calcFontSize(word.id) * word.text.length;
});

that.divideBy = pixNeeded < 7000 ? 2.5
  : pixNeeded < 9000 ? 2
  : pixNeeded < 12000 ? 1.7
  : pixNeeded < 13000 ? 1.6
  : pixNeeded < 15000 ? 1.5
  : pixNeeded < 16000 ? 1.4
  : pixNeeded < 17000 ? 1.3
  : 1;

if (that.h<600 ||that.w<500) // little window handling
{
  that.divideBy=1;
  that.scale=0.8;
  if(pixNeeded>15000) { //small window+lots of words handling by shrink font
    that.wordService.fontMax = 24;
    that.wordService.fontMin = 8;
  }

I'm using this.divideBy here in layout size:

 this.layout = d3.layout.cloud().size([that.w / that.divideBy, that.h /        that.divideBy])

is there any smarter algorithm ? or way to fit the g element to the outer div?

  1. After making the font size so words will not running out, I want that the words will cover all the div, I am able to do it after the cloud is on screen, by (SVG width)/(g width) = width scale and then apply the width scale manually to the g element . but how to do that in javascript ?

Upvotes: 2

Views: 3722

Answers (2)

Racheli Frish
Racheli Frish

Reputation: 211

To calculate the font-size, you have to create this scale:

var fontSizeScale = d3.scale.pow().exponent(5).domain([0,1]).range([ minFont, maxFont]);

and call it in fontSize function:

var maxSize = d3.max(that.data, function (d) {return d.size;});

// on the d3.layout.cloud()
  .fontSize(function (d) {
        return fontSizeScale(d.size/maxSize);
      })

To fit the bounds to your screen/div:

in the .on("end", drawCloud) function, call this function:

function zoomToFitBounds() {

      var X0 = d3.min( words, function (d) {
        return d.x - (d.width/2);
      }),
        X1 = d3.max( words, function (d) {
          return d.x + (d.width/2);
        });

      var Y0 = d3.min( words, function (d) {
          return d.y - (d.height/2);
        }),
        Y1 = d3.max( words, function (d) {
          return d.y + (d.height/2);
        });

      var scaleX = (X1 - X0) / (width);
      var scaleY = (Y1 - Y0) / (height);

      var scale = 1 / Math.max(scaleX, scaleY);

      var translateX = Math.abs(X0) * scale;
      var translateY = Math.abs(Y0) * scale;

      cloud.attr("transform", "translate(" +
        translateX + "," + translateY + ")" +
        " scale(" + scale + ")");
}

Upvotes: 6

Mukul Jain
Mukul Jain

Reputation: 1175

If you want words to resize according to there parent element's width then this might help

.style("font-size", function(d) { return Math.min(2 * r, (2 * r - 8) / this.getComputedTextLength() * 24) + "px"; });

r is dependent on the parent element

Not sure exactly, if this is what you are looking for

Upvotes: 0

Related Questions