Bladeren bron

word_cloud_graphics

kora 1 jaar geleden
bovenliggende
commit
dfc37863ca
2 gewijzigde bestanden met toevoegingen van 127 en 81 verwijderingen
  1. 63 53
      js/rectangles.js
  2. 64 28
      js/word_cloud.js

+ 63 - 53
js/rectangles.js

@@ -1,14 +1,20 @@
 class Rect {
     constructor(w, h, x1=0, y1=0, alpha=0, text = "", fontSize = 20){
-           this.w = Math.abs(w);
-           this.h = Math.abs(h);
-                this.x1 = x1;
-           this.y1 = y1;
-           this.alpha = alpha;
-           this.alphaRad = this.alpha*Math.PI/180;
-           this.text = text;
-           this.fontSize = fontSize;
-           this.initBoundingBox();
+        this.w = Math.abs(w);
+        this.h = Math.abs(h);
+        this.x1 = x1;
+        this.y1 = y1;
+        this.alpha = alpha;
+        this.alphaRad = this.alpha*Math.PI/180;
+        this.text = text;
+        this.fontSize = fontSize;
+        this.initBoundingBox();
+    }
+    refresh(){
+        this.w = Math.abs(this.w);
+        this.h = Math.abs(this.h);
+        this.alphaRad = this.alpha*Math.PI/180;
+        this.initBoundingBox();
     }
     getQuadrant(){
         if(0<=this.alphaRad<Math.PI/2) return 1;
@@ -17,14 +23,14 @@ class Rect {
         if(3*Math.PI/2<=this.alphaRad<2*Math.PI) return 4;
     }
     initBoundingBox(){
-       let cAlpha = Math.cos(this.alphaRad);
-       let sAlpha = Math.sin(this.alphaRad);
-       this.xx = [this.x1, this.x1 + this.w*cAlpha, this.x1 + this.w*cAlpha - this.h*sAlpha, this.x1 - this.h*sAlpha];
-       this.yy = [this.y1, this.y1 + this.w*sAlpha, this.y1 + this.w*sAlpha + this.h*cAlpha, this.y1 + this.h*cAlpha];
-       this.minX = Math.min(...this.xx);
-       this.maxX = Math.max(...this.xx);
-       this.minY = Math.min(...this.yy);
-       this.maxY = Math.max(...this.yy);
+        let cAlpha = Math.cos(this.alphaRad);
+        let sAlpha = Math.sin(this.alphaRad);
+        this.xx = [this.x1, this.x1 + this.w*cAlpha, this.x1 + this.w*cAlpha - this.h*sAlpha, this.x1 - this.h*sAlpha];
+        this.yy = [this.y1, this.y1 + this.w*sAlpha, this.y1 + this.w*sAlpha + this.h*cAlpha, this.y1 + this.h*cAlpha];
+        this.minX = Math.min(...this.xx);
+        this.maxX = Math.max(...this.xx);
+        this.minY = Math.min(...this.yy);
+        this.maxY = Math.max(...this.yy);
     }
 
     printCoords(showRectangles=true, maxFontSize=80, minFontSize=20){
@@ -42,58 +48,62 @@ class Rect {
         let rectCoordsHtml = ' x="'+this.x1+'" y="'+this.y1+'" width="'+(this.w)+'" height="'+(this.h)+'"';
         let rotateHtml = ' transform="rotate('+this.alpha+','+this.x1+','+this.y1+')"'
         if(this.text!=""){
-         let rectsHtml = showRectangles ? '<rect' + rectCoordsHtml + style + '/>' : "";
-         let textCoordsHtml = ' x="'+this.x1+'" y="'+(this.y1+2/3*this.h)+'"';
-         toRet = '<g' + rotateHtml + '>' +
-         rectsHtml +
-         '<text' + textCoordsHtml + ' font-family="Verdana" fill="RGB('+(2*this.fontSize)+','+(0)+','+(155-2*this.fontSize)+')" font-size="'+this.fontSize+'">' + this.text + '</text>' +
-         '</g>'
+            let colRGB = {
+                red: 155*(this.fontSize-minFontSize)/(maxFontSize-minFontSize),
+                green: 0,
+                blue: 155*(maxFontSize-this.fontSize)/(maxFontSize-minFontSize)
+            };
+            let rectsHtml = showRectangles ? '<rect' + rectCoordsHtml + style + '/>' : "";
+            let textCoordsHtml = ' x="'+this.x1+'" y="'+(this.y1+2/3*this.h)+'"';
+            toRet = '<g' + rotateHtml + '>' +
+            rectsHtml +
+            '<text' + textCoordsHtml + ' font-family="Verdana" fill="RGB('+colRGB.red+','+colRGB.green+','+colRGB.blue+')" font-size="'+this.fontSize+'">' + this.text + '</text>' +
+            '</g>'
         } else{
-          toRet = '<rect' + rectCoordsHtml + rotateHtml + style + '/>';
+            toRet = '<rect' + rectCoordsHtml + rotateHtml + style + '/>';
         }
-      return toRet;
+        return toRet;
     }
 
 }
 
+
 function rotate(rect, angle, x0, y0){
-let alpha1 = rect.alpha+angle;
-let angleRad = angle*Math.PI/180;
-let x1Temp = rect.x1-x0;
-let y1Temp= rect.y1-y0;
-let x11 = Math.cos(angleRad)*x1Temp - Math.sin(angleRad)*y1Temp + x0;
-let y11 = Math.sin(angleRad)*x1Temp + Math.cos(angleRad)*y1Temp + y0;
-return new Rect(rect.w, rect.h, x11, y11, alpha1, rect.text, rect.fontSize);
+    let alpha1 = rect.alpha+angle;
+    let angleRad = angle*Math.PI/180;
+    let x1Temp = rect.x1-x0;
+    let y1Temp= rect.y1-y0;
+    let x11 = Math.cos(angleRad)*x1Temp - Math.sin(angleRad)*y1Temp + x0;
+    let y11 = Math.sin(angleRad)*x1Temp + Math.cos(angleRad)*y1Temp + y0;
+    return new Rect(rect.w, rect.h, x11, y11, alpha1, rect.text, rect.fontSize);
 }
 
 function rotoTranslate(rect, angle, x0, y0){
- let alpha1 = rect.alpha+angle;
- let angleRad = angle*Math.PI/180;
- let x1Temp = rect.x1-x0;
- let y1Temp= rect.y1-y0;
- let x11 = Math.cos(angleRad)*x1Temp - Math.sin(angleRad)*y1Temp;
- let y11 = Math.sin(angleRad)*x1Temp + Math.cos(angleRad)*y1Temp;
- return new Rect(rect.w, rect.h, x11, y11, alpha1);
+    let alpha1 = rect.alpha+angle;
+    let angleRad = angle*Math.PI/180;
+    let x1Temp = rect.x1-x0;
+    let y1Temp= rect.y1-y0;
+    let x11 = Math.cos(angleRad)*x1Temp - Math.sin(angleRad)*y1Temp;
+    let y11 = Math.sin(angleRad)*x1Temp + Math.cos(angleRad)*y1Temp;
+    return new Rect(rect.w, rect.h, x11, y11, alpha1);
 }
 
 function checkColl(r1, r2){
 
-   // 1. Check bounding box collision:
-   if( r1.minX>r2.maxX || r1.maxX<r2.minX || r1.minY>r2.maxY || r1.maxY<r2.minY ) return false;
+    // 1. Check bounding box collision:
+    if( r1.minX>r2.maxX || r1.maxX<r2.minX || r1.minY>r2.maxY || r1.maxY<r2.minY ) return false;
 
-   let newR1 = rotoTranslate(r1, -r2.alpha, r2.x1, r2.y1);
-   if( newR1.minX>r2.w || newR1.maxX<0 || newR1.minY>r2.h || newR1.maxY<0 ) return false;
+    let newR1 = rotoTranslate(r1, -r2.alpha, r2.x1, r2.y1);
+    if( newR1.minX>r2.w || newR1.maxX<0 || newR1.minY>r2.h || newR1.maxY<0 ) return false;
 
-   let newR2 = rotoTranslate(r2, -r1.alpha, r1.x1, r1.y1);
-   if( newR2.minX>r1.w || newR2.maxX<0 || newR2.minY>r1.h || newR2.maxY<0 ) return false;
+    let newR2 = rotoTranslate(r2, -r1.alpha, r1.x1, r1.y1);
+    if( newR2.minX>r1.w || newR2.maxX<0 || newR2.minY>r1.h || newR2.maxY<0 ) return false;
 
-   // A Rectangle has a parametric description through s and t:
-   // (x1, y1) + t*(cAlpha, sAlpha ) + s*(-sAlpha, cAlphs)
-   // 0 <= t <= w, 0 <= s <= h.
-   //
-   // Start by limiting s through t range check
+    // A Rectangle has a parametric description through s and t:
+    // (x1, y1) + t*(cAlpha, sAlpha ) + s*(-sAlpha, cAlphs)
+    // 0 <= t <= w, 0 <= s <= h.
+    //
+    // Start by limiting s through t range check
 
-   return true;
+    return true;
 }
-
-

+ 64 - 28
js/word_cloud.js

@@ -122,7 +122,7 @@ function doWordCloud(words){
 
     // OVERALL GRAPHIC SETTINGS for the cloud container -- id, dimensions, position
 
-    let width = 0.5*window.innerWidth;
+    let width = 0.5*window.outerWidth;
     let height = 0.6*width;
   
     // append the svg object to the body of the page
@@ -147,12 +147,15 @@ function doWordCloud(words){
     // THE ACTUAL CLOUD
     svg = document.getElementById('wordcloudNetwork');
     console.log(svg);
-    console.log('CAZZO', svg.getBoundingClientRect());
+
+    let zoom = window.devicePixelRatio;
+    console.log('zoom', zoom);
+
     wcParameters = {
         svgWidth: svg.getBoundingClientRect().width,
         svgHeight: svg.getBoundingClientRect().height,
-        maxFontSize: 20,
-        minFontSize: 5
+        maxFontSize: 30/((1+zoom)/2),
+        minFontSize: 10/((1+zoom)/2)
     }
     let svgWords = hackWords(words, wcParameters);
     svg.innerHTML = svgWords;
@@ -190,8 +193,8 @@ function hackWords(words, parameters){
     let maxFontSize = parameters.maxFontSize;
     let minFontSize = parameters.minFontSize;
     console.log('weights', weights);
-    console.log(maxFontSize);
-    console.log(minFontSize);
+    console.log('maxFontSize', maxFontSize);
+    console.log('minFontSize',minFontSize);
     let stringOfWords = "";
 
     for(let ind=0; ind<words.length; ind++){
@@ -210,57 +213,69 @@ function createWordCloud(words, parameters){
 
     let actualUsefulWidth = parameters.svgWidth;
     let actualUsefulHeight = parameters.svgHeight;
+    console.log('Actual SVG dimensions', actualUsefulWidth, actualUsefulHeight);
+
+    maxFontSize = parameters.maxFontSize;
+    minFontSize = parameters.minFontSize;
 
     const rectObjs = []
     let allBooms = 0
     let attempts = 0;
-    
+    let outOfBorder = 0;
     for(let ind=0;ind<words.length;ind++){
     //for(let ind=0;ind<3;ind++){
 
+        // Control vars
+        if(allBooms>=50*(ind+1)) break;
+        attempts++;
+        let boom = false;
+
+        // word + bounding box parameters definition
         let word = words[ind];
         let id0 = "word"+ind;
-        console.log('id0', id0);
         let wordBB = document.getElementById(id0).getBoundingClientRect();
-
-        attempts++;
-        let boom = false;
-        // rectangle definition
         let fontSize = word.fontSize;
-        let width = wordBB.width;
-        let height = wordBB.height;
-        let xR = actualUsefulWidth + (Math.random()-0.5)*actualUsefulWidth - width;
-        let yR = actualUsefulHeight/2 + (Math.random()-0.5)*actualUsefulHeight - width;
-        //let xR = 0;
-        //let yR = 0;
-        //if(ind>0) yR = actualUsefulHeight-fontSize;
-        //if(ind>1) xR = actualUsefulWidth-width;
+        let width = wordBB.width*1;
+        let height = wordBB.height*1;
+        let multiplier = 0.1 + 0.4*(maxFontSize-fontSize)/(maxFontSize-minFontSize);
+        let xR = Math.floor(actualUsefulWidth/2 + randomRange(-multiplier*actualUsefulWidth, multiplier*actualUsefulWidth));
+        let yR = Math.floor(actualUsefulHeight/2 + randomRange(-multiplier*actualUsefulHeight, multiplier*actualUsefulHeight));
+        //console.log('x', 'y', xR, yR)
         let angle;
-        if(word.received/word.sent>2) angle = 90;
-        else if(word.received/word.sent<1/2) angle = 270;
-        angle = 0; 
+        if(word.received/word.sent>3) angle = -3;
+        else if(word.received/word.sent<0.3) angle = 3;
         let text = word.text;
         //console.log('Rect:', width, height, xR, yR, angle, text);
+
+        // 
         let newRect = new Rect(width, height, xR, yR, angle, text, fontSize);
-        //console.log('nnn', newRect);
+        boom = checkBorder(newRect, 0, actualUsefulWidth, 0, actualUsefulHeight)
+        if(boom){
+            outOfBorder++;
+            if(outOfBorder<30){
+                ind--;
+                continue;
+            } else{
+                boom = false;
+            }
+        }
         for(let rect of rectObjs){
             boom = checkColl(newRect, rect);
             if(boom) break;
         }
         if(boom){
             allBooms++;
-            if(allBooms<10) ind--;
-            else(allBooms = 0);
+            ind--;
             continue;
         }
-        allBooms = 0;
+//        allBooms = 0;
         rectObjs.push(newRect);
     }
     console.log('Attempted:', attempts);
     console.log('Placed:', rectObjs.length);
 
     const rectTexts = [];
-    rectObjs.forEach(rect => rectTexts.push(rect.printCoords(false)));
+    rectObjs.forEach(rect => rectTexts.push(rect.printCoords(false, maxFontSize, minFontSize)));
     let rects = rectTexts.join('\n');
 
     return rects;
@@ -271,3 +286,24 @@ function getFontSize(weight, minWeight, maxFontSize, minFontSize){
     let res = minFontSize + (maxFontSize-minFontSize)*r1/Math.sqrt(1+r1**2);
     return res;
 }
+
+function randomRange(a, b=0){
+    return (a-b)*Math.random()+b;
+}
+function randomInt(a){
+    return Math.floor(a*Math.random());
+}
+function randomRangeInt(a, b=0){
+    let ap = Math.floor(a);
+    let bp = Math.floor(b);
+    return Math.floor((ap-bp)*Math.random())+bp;
+}
+
+// Check border collision
+function checkBorder(rect, minX, maxX, minY, maxY){
+    if(rect.minX<minX) return true;
+    if(rect.maxX>maxX) return true;
+    if(rect.minY<minY) return true;
+    if(rect.maxY>maxY) return true;
+    return false;
+}