timdream / wordcloud2.js

Tag cloud/Wordle presentation on 2D canvas or HTML
https://wordcloud2-js.timdream.org/
MIT License
2.36k stars 511 forks source link

fix: maxRadius to avoid overflow #183

Open Ovilia opened 2 years ago

Ovilia commented 2 years ago

This PR fixes maxRadius so that text does not overflows the shape.

Before

Take shape: 'circle' and 'diamond' for example, when text list contains too many text, it will overflows the shape.

circle before diamod before

After

circle after diamond after

Test case used:

<html>
  <head>
    <style>
      body {
        margin: 0;
      }
      #main {
        border: 1px solid red;
        width: 400px;
        height: 400px;
      }
      #circle {
        position: absolute;
        left: 0;
        top: 0;
        width: 400px;
        height: 400px;
        border-radius: 200px;
        border: 1px solid blue;
      }
      #diamond {
        position: absolute;
        left: 58px;
        top: 58px;
        width: 282.8px;
        height: 282.8px;
        transform: rotate(45deg);
        transform-origin: 50% 50%;
        border: 1px solid blue;
      }
    </style>
  </head>
  <body>
    <canvas id="main"></canvas>
    <!-- <div id="circle"></div> -->
    <div id="diamond"></div>
    <script src="./src/wordcloud2.js"></script>
    <script>
      var data = [];
      for (var i = 0; i < 400; i++) {
        data.push([
          'wordcloud'.slice(0, Math.ceil(Math.random() * 9)),
          Math.round(Math.random() * 40) + 5,
        ]);
      }

      var canvas = document.getElementById('main');
      canvas.width = 800;
      canvas.height = 800;

      WordCloud(canvas, {
        list: data,
        ellipticity: 1,
        gridSize: 4,
        shape: 'diamond',
      });
    </script>
  </body>
</html>
timdream commented 2 years ago

Thank for the contribution.

I don't think the fix is correct. Math.floor(Math.max(ngx, ngy) / 2) is the distance to the nearest edge from the center, right? First of all, center can be moved, so you would need consider that. Second of all, what if the shape is a square and we do want to fill all four corners of the canvas? The proposed maxRadius in that case will not be enough.

Feel free to propose better logic (preferably without yet another options — there are too many of these and they are conflicting sometimes, as evidenced by this case — sorry for the bad catch-all API design!