WordCram

open-source word clouds for Processing

Follow WordCram on Twitter @wordcram

Ask a Question in the Forum /wordcram

Pull Requests Welcome on GitHub danbernier/WordCram

Latest News

WordCram 1.0.0 Released, for Processing 3.0

WordCram 0.6.2 Released

WordCram 0.6.1 Released

All posts

Shapes for WordCram

This has been a feature request for a long time: making WordCrams in arbitrary shapes, like Tagxedo does.

It’s currently slow, and a bit limited - you have to provide a java.awt.Shape, not (say) an image mask - but it’s a first step. I hope to package it up nicely for the next WordCram release.

Below is the guts of the code, but here’s the output:

wordcram-love

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class ShapeBasedPlacer implements WordPlacer, WordNudger {

  Area area;
  float minX;
  float minY;
  float maxX;
  float maxY;

  public ShapeBasedPlacer(Shape shape) {
    this.area = new Area(shape);

    Rectangle2D areaBounds = area.getBounds2D();
    this.minX = (float)areaBounds.getMinX();
    this.minY = (float)areaBounds.getMinY();
    this.maxX = (float)areaBounds.getMaxX();
    this.maxY = (float)areaBounds.getMaxY();
  }

  public PVector place(Word w, int rank, int count, int ww, int wh, int fw, int fh) {

    w.setProperty("width", ww);
    w.setProperty("height", wh);

    for (int i = 0; i < 1000; i++) {
      float newX = randomBetween(minX, maxX);
      float newY = randomBetween(minY, maxY);
      if (area.contains(newX, newY, ww, wh)) {
        return new PVector(newX, newY);
      }
    }

    return new PVector(-1, -1);
  }

  public PVector nudgeFor(Word word, int attempt) {
    PVector target = word.getTargetPlace();
    float wx = target.x;
    float wy = target.y;
    float ww = (Integer)word.getProperty("width");
    float wh = (Integer)word.getProperty("height");

    for (int i = 0; i < 1000; i++) {
      float newX = randomBetween(minX, maxX);
      float newY = randomBetween(minY, maxY);

      if (area.contains(newX, newY, ww, wh)) {
        return new PVector(newX - wx, newY - wy);
      }
    }

    return new PVector(-1, -1);
  }

  float randomBetween(float a, float b) {
    return a + random(b - a);
  }
}

void setup() {
  Shape heart = makeHeart();
  ShapeBasedPlacer shapeBasedPlacer = new ShapeBasedPlacer(heart);

  new WordCram(this)
    .withPlacer(shapeBasedPlacer)
    .withNudger(shapeBasedPlacer)
    .drawAll();
}

<<

>>