浏览代码

new wordcloud -- incomplete

Francesco 1 年之前
父节点
当前提交
e46bd7a0ad
共有 5 个文件被更改,包括 573 次插入129 次删除
  1. 2 1
      Persona.html
  2. 15 3
      css/place_people.css
  3. 99 0
      js/rectangles.js
  4. 338 0
      js/word_cloud copy.js
  5. 119 125
      js/word_cloud.js

+ 2 - 1
Persona.html

@@ -368,7 +368,7 @@
 								<div class="row">
 									<div class="col-9">
 										<div id="person_map" style="background-color: #fff; min-height:300px; margin-left:15px; margin-right:15px;">
-											<div id="myWordCloud"/>
+											<div id="myWordCloud" class="svg-container"/>
 												<div id="word_loader" class="loader"></div>
 											</div>
 										</div>
@@ -553,6 +553,7 @@
 	</footer>
 
 	<script src="js/people.js"></script>
+	<script src="js/rectangles.js"></script>
 	<script src="js/word_cloud.js"></script>
 
 	<!-- Bootstrap core JavaScript -->

+ 15 - 3
css/place_people.css

@@ -275,19 +275,31 @@ div#container {
   background-color: #2F4A6D;
 }
 
-svg {
-  width: 100%;
-  height: 100%;
+.svg-container {
+    display: inline-block;
+    position: relative;
+    width: 100%;
+    padding-bottom: 100%;
+    vertical-align: top;
+    overflow: auto;
+}
+.svg-content {
+    display: inline-block;
+    position: absolute;
+    top: 0;
+    left: 0;
 }
 
 .bar {
   fill: #80cbc4;
 }
 
+/*
 text {
   font-size: 0.5vw;
   fill: #000;
 }
+*/
 
 path {
   stroke: gray;

+ 99 - 0
js/rectangles.js

@@ -0,0 +1,99 @@
+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();
+    }
+    getQuadrant(){
+        if(0<=this.alphaRad<Math.PI/2) return 1;
+        if(Math.PI/2<=this.alphaRad<Math.PI) return 2;
+        if(Math.PI<=this.alphaRad<3*Math.PI/2) return 3;
+        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);
+    }
+
+    printCoords(showRectangles=true, maxFontSize=80, minFontSize=20){
+        let styleR = ' style="fill:red;stroke:black;stroke-width:2;opacity:0.5"';
+        let styleG = ' style="fill:green;stroke:black;stroke-width:2;opacity:0.5"';
+        let styleB = ' style="fill:blue;stroke:black;stroke-width:2;opacity:0.5"';
+        let style;
+        let selector = Math.floor(Math.random()*3);
+        //console.log('sel', selector);
+        if(selector==0) style=styleR;
+        if(selector==1) style=styleG;
+        if(selector==2) style=styleB;
+        //console.log('st', style);
+        let toRet = "";
+        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>'
+        } else{
+          toRet = '<rect' + rectCoordsHtml + rotateHtml + style + '/>';
+        }
+      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);
+}
+
+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);
+}
+
+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;
+
+   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;
+
+   // 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;
+}
+
+

+ 338 - 0
js/word_cloud copy.js

@@ -0,0 +1,338 @@
+
+/**
+ * QUERY SECTION
+ * 
+ *               */
+
+// SPARQL Query text -- 'prefixes' and 'thisUrlParams' defined in people.js; 
+let queryNetwork = prefixes + " SELECT COUNT(?event1) AS ?count1 COUNT(?event2) AS ?count2 ?uri2 SAMPLE(?label2) AS ?text \
+WHERE { \
+{?event1 rdf:type crm:EL1_Exchange_Letters . \
+?event_to rdfs:subClassOf ?event1; \
+rdf:type crm:EL2_Send_Letter ; \
+crm:P01_has_domain ?pc_to . \
+?pc_to crm:P02_has_range ?uri . \
+?uri rdfs:label ?label . \
+?event_from rdfs:subClassOf ?event1; \
+rdf:type crm:EL3_Receive_Letter; \
+crm:P01_has_domain ?pc_from . \
+?pc_from crm:P02_has_range ?uri2 . \
+?uri2 rdfs:label ?label2 . \
+FILTER (?uri = <" + thisUrlParams.link + ">) \
+} UNION { \
+?event2 rdf:type crm:EL1_Exchange_Letters . \
+?event_to rdfs:subClassOf ?event2; \
+rdf:type crm:EL3_Receive_Letter ; \
+crm:P01_has_domain ?pc_from . \
+?pc_from crm:P02_has_range ?uri . \
+?uri rdfs:label ?label . \
+?event_from rdfs:subClassOf ?event2; \
+rdf:type crm:EL2_Send_Letter; \
+crm:P01_has_domain ?pc_to . \
+?pc_to crm:P02_has_range ?uri2 . \
+?uri2 rdfs:label ?label2 . \
+FILTER (?uri = <" + thisUrlParams.link + ">) \
+} \
+}"
+
+// 'prepareQueryURL' defined in people.js
+let queryNet = prepareQueryURL(queryNetwork);
+
+// do the query, call data processor on successful output
+$.ajax({
+    url: queryNet,
+    dataType: "json",
+    success: (data) => handle_word_network(data)
+});
+
+
+
+/**
+ * COMPONENT CREATION SECTION
+ * 
+ *               */
+
+// Master function, takes data output from the query and creates the HTML for the Word Cloud component of the page
+function handle_word_network(json){
+    // Pre-process data
+    let tempArray = processQuery(json);
+    let words = prepareWords(tempArray);
+    // Create page elements
+    doListPersonNetwork(tempArray);
+    doWordCloud(words);
+}
+
+
+// Return structured object from raw query data for further processing
+function processQuery(json) {
+  
+    const tempArray = [];
+    
+    $.each(
+        json['results']['bindings'],
+        (index, value) => {
+          let text = value['text']['value'];
+          let link = value['uri2']['value'];
+          let sent = parseInt(value['count1']['value']);
+          let received = parseInt(value['count2']['value']);
+          let count = sent + received;
+          tempArray.push({'text': text, 'sent': sent, 'received': received, 'count': count, 'hlink': link});
+        }
+    );
+
+    tempArray.sort((a, b) => b.count - a.count);
+
+    return tempArray;
+
+}
+
+
+// Define font size, according to the number of words and limiting the impact of huge counts -- to refactor??
+function prepareWords(tempArray){
+
+    const words = [];
+
+    if (tempArray.length < 8) { // Less than 8 results -- font size is just = count/2 + constant
+      for (let k=tempArray.length-1; k>=0; k--) {
+        let text = tempArray[k]['text'];
+        let preSize = tempArray[k]['count'] + 36;
+        console.log('mann', preSize)
+        let link = tempArray[k]['hlink'];
+        words.push(
+            {
+                'text': text,
+                'size': preSize/2 + 6,
+                'hlink': link
+            }
+        );
+      }
+    } else { // More than 8 results -- font size = count except for especially "big" words
+      let temp = 0;
+      for (let k=tempArray.length-1; k>=0; k--) {
+        let text = tempArray[k]['text']; 
+        let count = tempArray[k]['count'];
+        let link = tempArray[k]['hlink'];
+        let preSize = 0;
+        if ((count - temp) > 50) {
+            preSize = temp + 12;
+          } else {
+            preSize = count;
+        }
+        words.push(
+            {
+                'text': text,
+                'size': preSize/2 + 6,
+                'hlink': link
+            }
+        );
+        temp = preSize;
+      }
+    }
+
+    console.log('tempArray', tempArray)
+    console.log('words', words)
+    
+    return words;
+
+}
+
+
+// Create formatted list of people in the network
+function doListPersonNetwork(tempArray){
+
+    let ArrayNames = "";
+
+    tempArray.forEach(element => {
+        ArrayNames +=
+        "<div class='item-place-person'>\
+            <div class='item-place-person-label'>" +
+                element['text'] +
+                "<br /><span class='num_occ'>[Lettere inviate: " + element['sent'] + "]</span>\
+                <br /><span class='num_occ'>[Lettere ricevute: " + element['received'] + "]</span>\
+                <br /><span class='num_occ'>[Totale corrispondenza: " + element['count'] + "]</span>\
+            </div>\
+            <div class='item-place-person-action'>\
+                <div class='persona' id='" + element['hlink'] +"'>\
+                    <i class='fa fa-user' style='cursor:pointer'></i>\
+                </div>\
+            </div>\
+        </div>";            
+    });
+
+    document.getElementById("list_person_network").innerHTML = ArrayNames;
+
+}
+
+
+// Create the word cloud
+function doWordCloud(myWords){
+    
+    // Clear word cloud div
+    $('#myWordCloud').empty();
+
+
+    // OVERALL GRAPHIC SETTINGS for the cloud container -- id, dimensions, position
+
+    // set the dimensions and margins of the graph
+    let modifierWidth = 0.4;
+    let modifierHeigth = 0.4;
+    let marginHeight = 0;
+    let marginWidth = 0;;
+
+    let margin = {
+        top: marginHeight,
+        right: marginWidth,
+        bottom: marginHeight,
+        left: marginWidth};
+    let width = modifierWidth*window.innerWidth;
+    let height = modifierHeigth*window.innerHeight;
+  
+    // append the svg object to the body of the page
+    let svg = d3.select("#myWordCloud")
+        .append("svg")
+        .attr("id", "wordcloudNetwork")
+        .attr("width", width + margin.left + margin.right)
+        .attr("height", height + margin.top + margin.bottom)
+        .attr("style", "border:1px solid black")
+        .append("g")
+        .attr("transform", "translate(" + (width*0.5) + "," + (height*0.5) + ")")
+        .attr("overflow","scroll");
+
+    // In case of empty cloud, draw special page and exit
+    if (myWords.length == 0){
+        drawEmptyWordCloud();
+        return;
+    }
+    
+
+    // THE ACTUAL CLOUD
+
+    // Constructs a new cloud layout instance. It runs an algorithm to find the position of words that suits your requirements
+    // Wordcloud features that are different from one word to the other must be here
+
+    let layout = d3.layout.cloud() // Constructs the cloud
+                          .size([1.5*width, 1.2*height]) // Sets width and height
+                          .words(myWords) // put words in; expects an array of objects. Format is free, it all depends on the definition of the functions that are applied to define the cloud structure.
+                          //
+                          // A js curiosity: ~ is a bitwise not operator. On a number, the double bitwise not ~~ has the net effect of giving the integer part, that is: floor on positives and ceiling on negatives.
+                          .rotate( () => { return ~~(Math.random() * 2);} )
+                          .fontSize( word => { return word['size']; } ) // font size of words
+                          .on("end", word => draw(word, svg));
+    layout.start();
+  
+}
+
+
+// Helper function for the Word Cloud --
+// it draws the words
+// Wordcloud features that are THE SAME from one word to the other can be here ??
+function draw(words, svg) {
+    let cloud = svg.selectAll("g text")
+        .data(words, word => word.text) // What does this do?
+
+        //Entering words
+        cloud.enter()
+             .append("text")
+             .style("font-family", "Impact")
+             .attr("text-anchor", "middle")
+             .attr('font-size', 1)
+             .append("a")
+             .attr("href", word => word.hlink)
+             .attr("data-toggle", "tooltip")
+             .text( word => { return word.text; });
+
+        //Entering and exiting words
+        cloud.transition()
+             .duration(600)
+             .style("font-size", function(d) { return d.size + "px"; })
+             .attr("transform", function(d) {
+                    return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
+             })
+             .style("fill-opacity", 1);
+
+        //Exiting words
+        cloud.exit()
+             .transition()
+              .duration(200)
+              .style('fill-opacity', 1e-6)
+              .attr('font-size', 1)
+              .remove();
+
+}
+
+
+// Helper function -- draw special empty word cloud if there are no occurrences
+function drawEmptyWordCloud(){
+
+    let wordIcon = "<div id='users_icon' class='no_info_icon'> \
+    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'> \
+      <!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d='M319.9 320c57.41 0 103.1-46.56 103.1-104c0-57.44-46.54-104-103.1-104c-57.41 0-103.1 46.56-103.1 104C215.9 273.4 262.5 320 319.9 320zM369.9 352H270.1C191.6 352 128 411.7 128 485.3C128 500.1 140.7 512 156.4 512h327.2C499.3 512 512 500.1 512 485.3C512 411.7 448.4 352 369.9 352zM512 160c44.18 0 80-35.82 80-80S556.2 0 512 0c-44.18 0-80 35.82-80 80S467.8 160 512 160zM183.9 216c0-5.449 .9824-10.63 1.609-15.91C174.6 194.1 162.6 192 149.9 192H88.08C39.44 192 0 233.8 0 285.3C0 295.6 7.887 304 17.62 304h199.5C196.7 280.2 183.9 249.7 183.9 216zM128 160c44.18 0 80-35.82 80-80S172.2 0 128 0C83.82 0 48 35.82 48 80S83.82 160 128 160zM551.9 192h-61.84c-12.8 0-24.88 3.037-35.86 8.24C454.8 205.5 455.8 210.6 455.8 216c0 33.71-12.78 64.21-33.16 88h199.7C632.1 304 640 295.6 640 285.3C640 233.8 600.6 192 551.9 192z'/> \
+    </svg> \
+    <p>Nessuna persona trovata</p> \
+    </div>";
+
+    $("#wordcloudNetwork").css("display", "none");
+    $("#references_network").css("display", "none");
+
+    document.getElementById("myWordCloud").innerHTML = wordIcon;
+
+}
+
+
+
+// Customized word cloud code
+
+// Takes a list of words, returns the innerHTML for a Word Cloud as a string containing multiple <g> svg elements
+function createWordCloud(words){
+
+    const rectObjs = []
+    let allBooms = 0
+    let attempts = 0;
+    for(let ind=0;ind<words.length;ind++){
+
+        let id0 = "word"+ind;
+        let praaaa = document.getElementById(id0).getBoundingClientRect();
+        //console.log('BB of '+id0, praaaa);
+
+        attempts++;
+        let boom = false;
+        // rectangle definition
+//        let width = 120 + Math.round(50*Math.random());
+//        let height = 40;
+        let fontSize = getFontSize(ind);
+        let width = praaaa.width;
+        //let height = fontSize;
+        let height = praaaa.height;
+        let xR = 1250 + Math.round( (Math.random()-0.5)*(1000 + 6*ind) );
+        let yR = 750 + Math.round( (Math.random()-0.5)*(400 + 4*ind) );
+        let angle = 90*(Math.floor(3*Math.random())-1);
+        let text = words[ind];
+        //console.log('Rect:', width, height, xR, yR, angle, text);
+        let newRect = new Rect(width, height, xR, yR, angle, text, fontSize);
+        //console.log('nnn', newRect);
+        for(let rect of rectObjs){
+            boom = checkColl(newRect, rect);
+            if(boom) break;
+        }
+        if(boom){
+            allBooms++;
+            if(allBooms<10) ind--;
+            else(allBooms = 0);
+            continue;
+        }
+        allBooms = 0;
+        rectObjs.push(newRect);
+    }
+    console.log('Attempted:', attempts);
+    console.log('Placed:', rectObjs.length);
+
+    const rectTexts = [];
+    rectObjs.forEach(rect => rectTexts.push(rect.printCoords()));
+    let rects = rectTexts.join('\n');
+
+    return rects;
+}
+
+function getFontSize(weight){
+    return Math.max(80-weight, 30);
+}

+ 119 - 125
js/word_cloud.js

@@ -55,10 +55,9 @@ $.ajax({
 // Master function, takes data output from the query and creates the HTML for the Word Cloud component of the page
 function handle_word_network(json){
     // Pre-process data
-    let tempArray = processQuery(json);
-    let words = prepareWords(tempArray);
+    let words = processQuery(json);
     // Create page elements
-    doListPersonNetwork(tempArray);
+    doListPersonNetwork(words);
     doWordCloud(words);
 }
 
@@ -87,56 +86,6 @@ function processQuery(json) {
 }
 
 
-// Define font size, according to the number of words and limiting the impact of huge counts -- to refactor??
-function prepareWords(tempArray){
-
-    const words = [];
-
-    if (tempArray.length < 8) { // Less than 8 results -- font size is just = count/2 + constant
-      for (let k=tempArray.length-1; k>=0; k--) {
-        let text = tempArray[k]['text'];
-        let preSize = tempArray[k]['count'] + 36;
-        console.log('mann', preSize)
-        let link = tempArray[k]['hlink'];
-        words.push(
-            {
-                'text': text,
-                'size': preSize/2 + 6,
-                'hlink': link
-            }
-        );
-      }
-    } else { // More than 8 results -- font size = count except for especially "big" words
-      let temp = 0;
-      for (let k=tempArray.length-1; k>=0; k--) {
-        let text = tempArray[k]['text']; 
-        let count = tempArray[k]['count'];
-        let link = tempArray[k]['hlink'];
-        let preSize = 0;
-        if ((count - temp) > 50) {
-            preSize = temp + 12;
-          } else {
-            preSize = count;
-        }
-        words.push(
-            {
-                'text': text,
-                'size': preSize/2 + 6,
-                'hlink': link
-            }
-        );
-        temp = preSize;
-      }
-    }
-
-    console.log('tempArray', tempArray)
-    console.log('words', words)
-    
-    return words;
-
-}
-
-
 // Create formatted list of people in the network
 function doListPersonNetwork(tempArray){
 
@@ -165,7 +114,7 @@ function doListPersonNetwork(tempArray){
 
 
 // Create the word cloud
-function doWordCloud(myWords){
+function doWordCloud(words){
     
     // Clear word cloud div
     $('#myWordCloud').empty();
@@ -173,94 +122,45 @@ function doWordCloud(myWords){
 
     // OVERALL GRAPHIC SETTINGS for the cloud container -- id, dimensions, position
 
-    // set the dimensions and margins of the graph
-    let modifierWidth = 0.4;
-    let modifierHeigth = 0.4;
-    let marginHeight = 0;
-    let marginWidth = 0;;
-
-    let margin = {
-        top: marginHeight,
-        right: marginWidth,
-        bottom: marginHeight,
-        left: marginWidth};
-    let width = modifierWidth*window.innerWidth;
-    let height = modifierHeigth*window.innerHeight;
+    let width = 0.5*window.innerWidth;
+    let height = 0.6*width;
   
     // append the svg object to the body of the page
     let svg = d3.select("#myWordCloud")
         .append("svg")
         .attr("id", "wordcloudNetwork")
-        .attr("width", width + margin.left + margin.right)
-        .attr("height", height + margin.top + margin.bottom)
+        .attr("preserveAspectRatio", "xMinYMin meet")
+        .attr("viewBox", "0 0 " + width + " " + height+'"')
+        .classed("svg-content", true)
+        .attr("width", width)
+        .attr("height", height)
         .attr("style", "border:1px solid black")
-        .append("g")
-        .attr("transform", "translate(" + (width*0.75) + "," + (height*0.78) + ")")
-        .attr("overflow","scroll");
 
     // In case of empty cloud, draw special page and exit
-    if (myWords.length == 0){
+    if (words.length == 0){
         drawEmptyWordCloud();
         return;
     }
     
 
-    // THE ACTUAL CLOUD
 
-    // Constructs a new cloud layout instance. It runs an algorithm to find the position of words that suits your requirements
-    // Wordcloud features that are different from one word to the other must be here
-
-    let layout = d3.layout.cloud() // Constructs the cloud
-                          .size([1.5*width, 1.2*height]) // Sets width and height
-                          .words(myWords) // put words in; expects an array of objects. Format is free, it all depends on the definition of the functions that are applied to define the cloud structure.
-                          //
-                          // A js curiosity: ~ is a bitwise not operator. On a number, the double bitwise not ~~ has the net effect of giving the integer part, that is: floor on positives and ceiling on negatives.
-                          .rotate( () => { return ~~(Math.random() * 2);} )
-                          .fontSize( word => { return word['size']; } ) // font size of words
-                          .on("end", word => draw(word, svg));
-    layout.start();
-  
-}
-
-
-// Helper function for the Word Cloud --
-// it draws the words
-// Wordcloud features that are THE SAME from one word to the other can be here ??
-function draw(words, svg) {
-    let cloud = svg.selectAll("g text")
-        .data(words, word => word.text) // What does this do?
-
-        //Entering words
-        cloud.enter()
-             .append("text")
-             .style("font-family", "Impact")
-             .attr("text-anchor", "middle")
-             .attr('font-size', 1)
-             .append("a")
-             .attr("href", word => word.hlink)
-             .attr("data-toggle", "tooltip")
-             .text( word => { return word.text; });
-
-        //Entering and exiting words
-        cloud.transition()
-             .duration(600)
-             .style("font-size", function(d) { return d.size + "px"; })
-             .attr("transform", function(d) {
-                    return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
-             })
-             .style("fill-opacity", 1);
-
-        //Exiting words
-        cloud.exit()
-             .transition()
-              .duration(200)
-              .style('fill-opacity', 1e-6)
-              .attr('font-size', 1)
-              .remove();
+    // THE ACTUAL CLOUD
+    svg = document.getElementById('wordcloudNetwork');
+    console.log(svg);
+    console.log('CAZZO', svg.getBoundingClientRect());
+    wcParameters = {
+        svgWidth: svg.getBoundingClientRect().width,
+        svgHeight: svg.getBoundingClientRect().height,
+        maxFontSize: 20,
+        minFontSize: 5
+    }
+    let svgWords = hackWords(words, wcParameters);
+    svg.innerHTML = svgWords;
 
+    let wordCloudText = createWordCloud(words, wcParameters);
+    svg.innerHTML = wordCloudText;
 }
 
-
 // Helper function -- draw special empty word cloud if there are no occurrences
 function drawEmptyWordCloud(){
 
@@ -277,3 +177,97 @@ function drawEmptyWordCloud(){
     document.getElementById("myWordCloud").innerHTML = wordIcon;
 
 }
+
+
+/*****************************
+* Customized word cloud code *
+*****************************/
+
+function hackWords(words, parameters){
+
+    let weights = words.map(word => word.count);
+    let minWeight = Math.min(...weights);
+    let maxFontSize = parameters.maxFontSize;
+    let minFontSize = parameters.minFontSize;
+    console.log('weights', weights);
+    console.log(maxFontSize);
+    console.log(minFontSize);
+    let stringOfWords = "";
+
+    for(let ind=0; ind<words.length; ind++){
+
+        let word = words[ind];
+        word.fontSize = getFontSize(words[ind].count, minWeight, maxFontSize, minFontSize);
+        stringOfWords = stringOfWords+
+        '<text x="100" y ="' + (maxFontSize + maxFontSize*ind).toString() + '" + font-family="Verdana" font-size="'+(word.fontSize)+'" id="word' + ind + '">'+words[ind].text+'</text>\n';
+    }
+    return stringOfWords;
+}
+
+
+// Takes a list of words, returns the innerHTML for a Word Cloud as a string containing multiple <g> svg elements
+function createWordCloud(words, parameters){
+
+    let actualUsefulWidth = parameters.svgWidth;
+    let actualUsefulHeight = parameters.svgHeight;
+
+    const rectObjs = []
+    let allBooms = 0
+    let attempts = 0;
+    
+    for(let ind=0;ind<words.length;ind++){
+    //for(let ind=0;ind<3;ind++){
+
+        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 angle;
+        if(word.received/word.sent>2) angle = 90;
+        else if(word.received/word.sent<1/2) angle = 270;
+        angle = 0; 
+        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);
+        for(let rect of rectObjs){
+            boom = checkColl(newRect, rect);
+            if(boom) break;
+        }
+        if(boom){
+            allBooms++;
+            if(allBooms<10) ind--;
+            else(allBooms = 0);
+            continue;
+        }
+        allBooms = 0;
+        rectObjs.push(newRect);
+    }
+    console.log('Attempted:', attempts);
+    console.log('Placed:', rectObjs.length);
+
+    const rectTexts = [];
+    rectObjs.forEach(rect => rectTexts.push(rect.printCoords(false)));
+    let rects = rectTexts.join('\n');
+
+    return rects;
+}
+
+function getFontSize(weight, minWeight, maxFontSize, minFontSize){
+    let r1 = weight/10*minWeight - 1/10; // between 0 and a big num
+    let res = minFontSize + (maxFontSize-minFontSize)*r1/Math.sqrt(1+r1**2);
+    return res;
+}