4

I keep getting the error: Error: attribute transform: Expected number, "translate(,)rotate(0)" when the word cloud tries to update. All the words then stack on top of each other. Any reason it would work on the first pass but not the second?

var words = [{"text" : "One", "size" : 10}, {"text" : "Two", "size" : 10}, 
{"text" : "Three", "size" : 10}, {"text" : "Four", "size" : 10}, {"text" : "Five", "size" : 10}, 
{"text" : "Six", "size" : 10}, {"text" : "Seven", "size" : 10}, {"text" : "Eight", "size" : 10},
{"text" : "Nine", "size" : 10}, {"text" : "Ten", "size" : 10}, {"text" : "Eleven", "size" : 10}, 
{"text" : "Twelve", "size" : 10}, {"text" : "Thirteen", "size" : 10}, {"text" : "Fourteen", "size" : 10},
{"text" : "Fifteen", "size" : 10}, {"text" : "Sixteen", "size" : 10}, {"text" : "Seventeen", "size" : 10},
{"text" : "Eighteen", "size" : 10}, {"text" : "Nineteen", "size" : 10}, {"text" : "Twenty", "size" : 10}];

localStorage.setItem('words', JSON.stringify(words));

var duration = 50;



var cloudGroup = d3.select("#d3").append("svg")
   .attr("width", 1000)
   .attr("height", 1000)
   .append("g")
   .attr("transform", "translate(500,500)");

d3.layout.cloud()
     .size([1000, 1000])
     .words(words.map(function(d) {
         var result = {text: d.text, size: d.size};
         return result;
     }))
     .padding(0)
     .rotate(0)
     .font("Impact")
     .fontSize(function(d) { return 10; })
     .on("end", draw)
     .start();



function draw(words) {
 cloudData = cloudGroup
     .selectAll("text")
     .data(words);

 // This part should deal with (newly) entering data
 cloudData.enter().append("text")
     .style("font-size", "0px")
     .style("font-family", "Impact")
     .attr("text-anchor", "middle")
     .attr("transform", function(d) {
         return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
     })
     .attr("class", "word")
     .attr("id", function(d){
      return d.text
     })
     .text(function(d) { return d.text; })
     .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });


 // This with updating existing data
 cloudData
     .transition().duration(duration).style("font-size", "0px")
     .remove()
     .style("font-size", "0px")
     .text(function(d) { return d.text; })
     .attr("transform", function(d) {
        return "translate(" + [d.x, d.y] + ")rotate(0)";
      })
     .transition().duration(duration).style("font-size", function(d) { return d.size + "px"; });

cloudData.exit()
.transition()
    .duration(200)
    .style('fill-opacity', 1e-6)
    .attr('font-size', 1)
    .remove();
}


$('.word').on({
  'click' : function(){
var clickedWord = this.id;
var words = JSON.parse(localStorage.getItem('words'));

for(var i in words){
  if(words[i].text == clickedWord){
    words[i].size += 1;
  }
}
localStorage.setItem('words', JSON.stringify(words));
update();
 }
 });

function update() {
words = JSON.parse(localStorage.getItem('words'));
draw(words);
}
codycodes
  • 95
  • 8
  • Looks like your error has to do when updating existing `CloudData`. I'm assuming that your `.attr("transform" ....)` is not being passed a valid value for `d`, when it is expecting an integer. – Evan Bechtol May 17 '16 at 19:51
  • I see your error. On this line you are missing a semicolon `return d.text`. This is in the code segment of `CloudData` that deals with (newly) entering data, right above the existing data segment – Evan Bechtol May 17 '16 at 19:53
  • Just tried adding one in and it's still not working. – codycodes May 17 '16 at 20:00
  • Looks like the second time around d is only getting: Object {text: "One", size: 10} Object {text: "Two", size: 10} – codycodes May 17 '16 at 20:11
  • Check out this post, it may help with your for-in loop: http://stackoverflow.com/a/9329476/4515720 – Evan Bechtol May 17 '16 at 20:18
  • 1
    You have to compute the layout again. Right now, you are computing the layout only the first time, but not when updating. Compute the layout again when you update and you'll have correct `d.x` and `d.y` values. – Gerardo Furtado May 17 '16 at 23:00

1 Answers1

1

Wouldn't you have to update the cloud.layout at your update function? I altered your code in order to get the following result.

var words = [{
    "text": "One",
    "size": 10
}, {
    "text": "Two",
    "size": 10
}, {
    "text": "Three",
    "size": 10
}, {
    "text": "Four",
    "size": 10
}, {
    "text": "Five",
    "size": 10
}, {
    "text": "Six",
    "size": 10
}, {
    "text": "Seven",
    "size": 10
}, {
    "text": "Eight",
    "size": 10
}, {
    "text": "Nine",
    "size": 10
}, {
    "text": "Ten",
    "size": 10
}, {
    "text": "Eleven",
    "size": 10
}, {
    "text": "Twelve",
    "size": 10
}, {
    "text": "Thirteen",
    "size": 10
}, {
    "text": "Fourteen",
    "size": 10
}, {
    "text": "Fifteen",
    "size": 10
}, {
    "text": "Sixteen",
    "size": 10
}, {
    "text": "Seventeen",
    "size": 10
}, {
    "text": "Eighteen",
    "size": 10
}, {
    "text": "Nineteen",
    "size": 10
}, {
    "text": "Twenty",
    "size": 10
}];

var duration = 50;



var cloudGroup = d3.select("#d3").append("svg")
    .attr("width", 500)
    .attr("height", 500)
    .append("g")
    .attr("transform", "translate(150,150)");

d3.layout.cloud()
    .size([500, 500])
    .words(words.map(function(d) {
        var result = {
            text: d.text,
            size: d.size
        };
        return result;
    }))
    .padding(0)
    .rotate(0)
    .font("Impact")
    .fontSize(function(d) {
        return 10;
    })
    .on("end", draw)
    .start();



function draw(words) {
    cloudData = cloudGroup.selectAll("text").data(words);

    // This part should deal with (newly) entering data
    cloudData.enter().append("text")
        .style("font-size", "0px")
        .style("font-family", "Impact")
        .attr("text-anchor", "middle")
        .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .attr("class", "word")
        .attr("id", function(d) {
            return d.text
        })
        .text(function(d) {
            return d.text;
        })
        .transition().duration(duration).style("font-size", function(d) {
            return d.size + "px";
        });


    // This with updating existing data
    cloudData
        .transition().duration(duration).style("font-size", "0px")
        .remove()
        .style("font-size", "0px")
        .text(function(d) {
            return d.text;
        })
        .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(0)";
        })
        .transition().duration(duration).style("font-size", function(d) {
            return d.size + "px";
        });

    cloudData.exit()
        .transition()
        .duration(200)
        .style('fill-opacity', 1e-6)
        .attr('font-size', 1)
        .remove();
}


$('.word').on({
    'click': function() {
        var clickedWord = this.id;

        for (var i in words) {
            if (words[i].text === clickedWord) {
                words[i].size += 4;
            }
        }
        update(words);
    }
});

function update() {
    d3.layout.cloud()
        .size([500, 500])
        .words(words.map(function(d) {
            var result = {
                text: d.text,
                size: d.size
            };
            return result;
        }))
        .padding(0)
        .rotate(0)
        .font("Impact")
        .fontSize(function(d) {
            return d.size;
        })
        .on("end", draw)
        .start();
}
<div id="d3">
         </div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.3.min.js" integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo=" crossorigin="anonymous"></script>
<script src="https://www.jasondavies.com/wordcloud/cloud.min.js"></script>
torresomar
  • 2,219
  • 2
  • 16
  • 28