Remove direct references to wordle: don't want to tramp on any toes, or get into trademark problems. Also add cancelability and font selection.
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 12 Dec 2008 16:08:44 -0500
changeset 8 177f4022f463
parent 7 266549722e4e
child 9 c7f0ffcfb541
push id1
push userbsmedberg@mozilla.com
push dateFri, 12 Dec 2008 21:25:26 +0000
Remove direct references to wordle: don't want to tramp on any toes, or get into trademark problems. Also add cancelability and font selection.
jswordle.js
wordle.html
wordmap.html
wordmap.js
rename from wordle.html
rename to wordmap.html
--- a/wordle.html
+++ b/wordmap.html
@@ -1,26 +1,37 @@
 <head>
-  <title>Trying to replicate wordle.net</title>
+  <title>WordMap</title>
   <style type="text/css">
     td {
       vertical-align: top;
     }
   </style>
 </head>
 <body>
+  <h1>Word Maps</h1>
+
+  <p>The word maps generated by <a href="http://www.wordle.net/">wordle.net</a> have been going around the
+  Mozilla community. They are really pretty, but I wanted to hack out
+  the output and algorithm, and avoid the unholy Java monster. So I
+  recreated it using the HTML &lt;canvas&gt; element and JavaScript.
+
+  <p>Note: currently requires Firefox 3.1. The codebase can be found
+  at http://hg.mozilla.org/users/bsmedberg_mozilla.com/wordmap if
+  you'd like to test/help!
+
   <div>
-  <input type="button" value="Get Words" onclick="drawasync()">
+  <input type="button" value="Wordmap of BSBlog" onclick="drawasync()">
+  Choose a font:
+  <input type="text" value="Papyrus, URW Palladio L" id="font" onchange="setFont()">
+  Status: <span id="status"></span>
+  <input type="button" value="Stop" onclick="gCurDraw = null">
   </div>
 
-  <table>
-   <tr>
-    <td>
-     <canvas width="800" height="800" id="cc" style="border: 1px solid black;"></canvas>
-    <td>
-     <pre id="status"></pre>
-  </table>
+  <canvas width="800" height="800" id="cc"
+    style="border: 1px solid black; display: block"></canvas>
 
+  <canvas width="800" height="800" id="chidden" style="display: none"></canvas>
   <iframe src="about:blank" id="i" style="display: none"></iframe>
 
-  <script type="application/javascript;version=1.8" src="jswordle.js">
+  <script type="application/javascript;version=1.8" src="wordmap.js">
   </script>
 </body>
rename from jswordle.js
rename to wordmap.js
--- a/jswordle.js
+++ b/wordmap.js
@@ -1,12 +1,21 @@
 const kWidth = 800;
 const kHeight = 800;
 const kParanoid = false;
-const kVerticalRatio = 0.7;
+
+var gFont;
+
+function setFont()
+{
+  gFont = $('font').value;
+}
+setFont();
+
+const kVerticalRatio = 0.35;
 
 const commonWords = [
   'the',
   'of',
   'to',
   'and',
   'a',
   'in',
@@ -104,17 +113,17 @@ commonWordMap[word] = true;
 function $(id) {
   return document.getElementById(id);
 }
 
 const statusel = $('status');
 
 function setStatus(msg)
 {
-  statusel.textContent += msg + "\n";
+  statusel.textContent = msg;
 }
 
 function getOwnProperties(o)
 {
   for (let p in o)
     if (o.hasOwnProperty(p))
       yield [p, o[p]];
 }
@@ -209,20 +218,16 @@ function hitTest(fullimg, wordimg, x, y)
 
   if (fullimg.minx === undefined)
     throw Error("Nothing placed on fullimg yet?");
 
   if (x > fullimg.maxx ||
       y > fullimg.maxy ||
       x + wordimg.width < fullimg.minx ||
       y + wordimg.height < fullimg.miny) {
-    /*
-    setStatus("outside of bounds: " + [x, y, wordimg.width, wordimg.height] + ", " +
-	      [fullimg.minx, fullimg.miny, fullimg.maxx, fullimg.maxy]);
-     */
     return false;
   }
 
   for (let wy = wordimg.height - 1; wy >= 0; --wy) {
     let widx = wy * wordimg.width * 4;
     let widxend = widx + (wordimg.width * 4);
 
     let fidx = ((y + wy) * fullimg.width + x) * 4;
@@ -245,18 +250,16 @@ function hitTest(fullimg, wordimg, x, y)
   }
   return false;
 }
 
 function slide(fullimg, wordimg, x1, y1, x2, y2)
 {
   let hitting = hitTest(fullimg, wordimg, x1, y1);
 
-  setStatus("started slide hitting: " + hitting);
-
   let steps = Math.max(Math.abs(x2 - x1), Math.abs(y2 - y1));
 
   for (let step = 0; step < steps; ++step) {
     let ix = Math.floor(x1 + (x2 - x1) * step / steps);
     let iy = Math.floor(y1 + (y2 - y1) * step / steps);
     if (hitTest(fullimg, wordimg, ix, iy) != hitting)
       return [ix, iy];
   }
@@ -301,17 +304,17 @@ function merge(fullimg, wordimg, x, y)
     fullimg.miny = Math.min(fullimg.miny, y);
     fullimg.maxx = Math.max(fullimg.maxx, x + wordimg.width);
     fullimg.maxy = Math.max(fullimg.maxy, y + wordimg.height);
   }
 }
 
 function drawWord(cx, word, size, vertical)
 {
-  cx.font = size + 'px Papyrus';
+  cx.font = size + 'px ' + gFont;
   let width = cx.measureText(word).width;
 
   let geth, getw, _go;
 
   if (vertical) {
     geth = width + size * 2;
     getw = size * 3;
 
@@ -362,61 +365,70 @@ function simpletest(cx, imgdata)
 }
 
 function draw()
 {
   statusel.textContent = '';
 
   let words = getWordList();
 
-  let cx = $('cc').getContext('2d');
+  let usercx = $('cc').getContext('2d');
+
+  let cx = $('chidden').getContext('2d');
   cx.clearRect(0, 0, kWidth, kHeight);
 
   cx.textBaseline = 'top';
   cx.shadowColor = "rgba(0, 0, 0, 0.3)";
 
   let imgdata = cx.getImageData(0, 0, kWidth, kHeight);
 
   /* comment out testing code */
 
   // simpletest(cx, imgdata);
 
   let wdata, wshadow, word, size, vertical, x, y;
+
+  let totalcount = Math.min(words.length, 200);
+
   /*
    * place the first word in a position randomly
-   */ 
+   */
   [word, size] = words[0];
-  vertical = Math.random() < kVerticalRatio * size / 88;
+  setStatus("Placing word '" + word + "': 1/" + totalcount);
+  yield;
+
+  vertical = Math.random() < kVerticalRatio;
   [wdata, wshadow] = drawWord(cx, word, size, vertical);
   x = normalInt(0, kWidth - wdata.width, 2);
   y = normalInt(0, kHeight - wdata.height, 2);
   merge(imgdata, wdata, x, y);
 
-  yield;
+  usercx.putImageData(imgdata, 0, 0);
   
   for (let i = 1; i < 200; ++i) {
     let [word, size] = words[i];
 
-    vertical = Math.random() < kVerticalRatio * size / 88;
+    setStatus("Placing word '" + word + "': " + (i + 1) + "/" + totalcount);
+    yield;
+
+    vertical = Math.random() < kVerticalRatio;
     [wdata, wshadow] = drawWord(cx, word, size, vertical);
 
     for (let r in placeWord(imgdata, wshadow)) {
       if (r) {
 	[x, y] = r;
 	merge(imgdata, wdata, x, y);
       }
       else {
 	yield;
       }
     }
 
-    yield;
+    usercx.putImageData(imgdata, 0, 0);
   }
-
-  cx.putImageData(imgdata, 0, 0);
 }
 
 function placeWord(imgdata, wdata)
 {
   let x = normalInt(0, kWidth - wdata.width, 1);
   let y = normalInt(0, kHeight - wdata.height, 1);
   for (let t = 1; t < 20; ++t) {
     let x2 = normalInt(0, kWidth - wdata.width, t);
@@ -438,18 +450,20 @@ function placeWord(imgdata, wdata)
 var gCurDraw;
 
 function drawasync()
 {
   if (gCurDraw)
     gCurDraw.close();
 
   function doSomeWork() {
+    if (!gCurDraw)
+      return;
     try {
       gCurDraw.next();
-      setTimeout(doSomeWork, 0);
+      setTimeout(doSomeWork, 1);
     }
     catch (e if e instanceof StopIteration) { }
   }
 
   gCurDraw = draw();
-  setTimeout(doSomeWork, 0);
+  setTimeout(doSomeWork, 1);
 }
\ No newline at end of file