I use a lot of different JavaScript libraries to accomplish many things in my job. I am often impressed with the tools that are readily available and free to accomplish these many tasks. However as a developer in 2016 some of these libraries forget that we are now a society that doesn’t look at things on a singular resolution. You would think that these developers would think about responsiveness whenever they create their libraries. If they were to do so it would make my job easier along with other developers.
As a professional it is my civic duty to not only create sites that not only function well, but they must also look good at almost any resolution. At certain times i will judge a site on how it looks on smaller screens, whether they used WordPress, Angular (yuck, EmberJS is better) and css for certain UI elements . There is very little excuse to not put out a quality product to the world.
I will say in the defense of some of those who create content that developing a JavaScript library can be a huge process. I cannot overly complain about the quality of work done by Jason Davies with his world cloud generator. It functionally works flawlessly for my use cases.
However, my biggest complaint about the library was its inability to render properly when the screen size changes. This may have been an oversight during development or this still may be a future feature we do not know about. As of today there isn’t a solution available online until today.
There are two things we must focus upon when setting up the component. The first being container size. As a user shrinks and grows their browser the parent container which holds the word cloud will change in size as well. In order to respond to such changes we must add an event listener to the windows resize event.
var frequency_list = [{"text":"study","size":40},{"text":"motion","size":15},{"text":"forces","size":10},{"text":"electricity","size":15},{"text":"movement","size":10},{"text":"relation","size":5},{"text":"things","size":10},{"text":"force","size":5},{"text":"ad","size":5},{"text":"energy","size":85},{"text":"living","size":5},{"text":"nonliving","size":5},{"text":"laws","size":15},{"text":"speed","size":45},{"text":"velocity","size":30},{"text":"define","size":5},{"text":"constraints","size":5},{"text":"universe","size":10},{"text":"physics","size":120},{"text":"describing","size":5},{"text":"matter","size":90},{"text":"physics-the","size":5},{"text":"world","size":10},{"text":"works","size":10},{"text":"science","size":70},{"text":"interactions","size":30},{"text":"studies","size":5},{"text":"properties","size":45},{"text":"nature","size":40},{"text":"branch","size":30},{"text":"concerned","size":25},{"text":"source","size":40},{"text":"google","size":10},{"text":"defintions","size":5},{"text":"two","size":15},{"text":"grouped","size":15},{"text":"traditional","size":15},{"text":"fields","size":15},{"text":"acoustics","size":15},{"text":"optics","size":15},{"text":"mechanics","size":20},{"text":"thermodynamics","size":15},{"text":"electromagnetism","size":15},{"text":"modern","size":15},{"text":"extensions","size":15},{"text":"thefreedictionary","size":15},{"text":"interaction","size":15},{"text":"org","size":25},{"text":"answers","size":5},{"text":"natural","size":15},{"text":"objects","size":5},{"text":"treats","size":10},{"text":"acting","size":5},{"text":"department","size":5},{"text":"gravitation","size":5},{"text":"heat","size":10},{"text":"light","size":10},{"text":"magnetism","size":10},{"text":"modify","size":5},{"text":"general","size":10},{"text":"bodies","size":5},{"text":"philosophy","size":5},{"text":"brainyquote","size":5},{"text":"words","size":5},{"text":"ph","size":5},{"text":"html","size":5},{"text":"lrl","size":5},{"text":"zgzmeylfwuy","size":5},{"text":"subject","size":5},{"text":"distinguished","size":5},{"text":"chemistry","size":5},{"text":"biology","size":5},{"text":"includes","size":5},{"text":"radiation","size":5},{"text":"sound","size":5},{"text":"structure","size":5},{"text":"atoms","size":5},{"text":"including","size":10},{"text":"atomic","size":10},{"text":"nuclear","size":10},{"text":"cryogenics","size":10},{"text":"solid-state","size":10},{"text":"particle","size":10},{"text":"plasma","size":10},{"text":"deals","size":5},{"text":"merriam-webster","size":5},{"text":"dictionary","size":10},{"text":"analysis","size":5},{"text":"conducted","size":5},{"text":"order","size":5},{"text":"understand","size":5},{"text":"behaves","size":5},{"text":"en","size":5},{"text":"wikipedia","size":5},{"text":"wiki","size":5},{"text":"physics-","size":5},{"text":"physical","size":5},{"text":"behaviour","size":5},{"text":"collinsdictionary","size":5},{"text":"english","size":5},{"text":"time","size":35},{"text":"distance","size":35},{"text":"wheels","size":5},{"text":"revelations","size":5},{"text":"minute","size":5},{"text":"acceleration","size":20},{"text":"torque","size":5},{"text":"wheel","size":5},{"text":"rotations","size":5},{"text":"resistance","size":5},{"text":"momentum","size":5},{"text":"measure","size":10},{"text":"direction","size":10},{"text":"car","size":5},{"text":"add","size":5},{"text":"traveled","size":5},{"text":"weight","size":5},{"text":"electrical","size":5},{"text":"power","size":5}];
function resize() {
document.getElementById("word-cloud").empty();
setup();
}
function fontSize(d) { return d.size; }
function setup() {
var color = d3.scale.linear()
.domain([0,1,2,3,4,5,6,10,15,20,100])
.range(["#ddd", "#ccc", "#bbb", "#aaa", "#999", "#888", "#777", "#666", "#555", "#444", "#333", "#222"]);
d3.layout.cloud().size([800, 300])
.words(frequency_list)
.rotate(0)
.fontSize(fontSize)
.on("end", draw)
.start();
function draw(words) {
d3.select("word-cloud").append("svg")
.attr("width", 850)
.attr("height", 350)
.attr("class", "wordcloud")
.append("g")
// without the transform, words words would get cutoff to the left and top, they would
// appear outside of the SVG area
.attr("transform", "translate(320,200)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("fill", function(d, i) { return color(i); })
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
setup();
window.addEventListener("resize", resize());
The second item we need to focus upon is after the resize is complete. Once the resize is complete you will notice that the font size may not be relative to the size of the parent’s container. In other words you will get something like this: Of course this may work in some cases, but I doubt that your user will like what they are viewing in their browser. In order to work around this we must scale our font sizes. The scaling of the the fonts is inexact science and may take some tweaking on your part. The overall goal is to create sizes for your fonts based upon the the size of the parent container of the word cloud.
var frequency_list = [{"text": "sample", "size": "xl"}, {"text": "demo", "size": "m"}]
function fontSize(d) {
var fontSizes = {
"s":[8, 10, 12, 14],
"m":[16, 20, 24, 28],
"l":[36, 42, 48, 54],
"xl":[48, 56, 64, 72]
},
width = document.getElementById("word-cloud").clientWidth,
fontScale = 0;
if(width < 400) {
fontScale = 0;
}
else if() {
fontScale = 1;
}
else if() {
fontScale = 2;
}
else {
fontScale = 3;
}
return fontSizes[d.size][fontScale];
}
The third and final point is the position of the word cloud svg container itself. This was probably the most difficult thing to accomplish so my hard work is your reward. A few notes on what is happening during the resize and initial setup. Once the initial setup is complete and drawn on the screen the library place the svg container way off center from its parent div.
var svgWidth = document.getElementById("word-cloud").getElementByTagName("svg").getElementByTagName("g").getBoundingClientRect().width,
svgHeight = document.getElementById("word-cloud").getElementByTagName("svg").getElementByTagName("g").getBoundingClientRect().height;
var svgLeftEdge = document.getElementById("word-cloud").getElementByTagName("svg").borderEdge.left,
gLeftEdge = document.getElementById("word-cloud").getElementByTagName("svg").getElementByTagName("g").borderEdge.left;
var svgTopEdge = document.getElementById("word-cloud").getElementByTagName("svg").borderEdge.top,
gTopEdge = document.getElementById("word-cloud").getElementByTagName("svg").getElementByTagName("g").borderEdge.top;
var wHeight = document.getElementById("word-cloud").getElementByTagName("svg").getBoundingClientRect().height;
var wWidth = document.getElementById("word-cloud").getElementByTagName("svg").getBoundingClientRect().width;
var tHeight = (svgTopEdge - gTopEdge) + ((wHeight - svgHeight)/2);
var tWidth = (svgLeftEdge + gLeftEdge.abs()) + ((wWidth - svgWidth)/2);
document.getElementById("word-cloud").getElementByTagName("svg").getElementByTagName("g").attributes['transform'] = "translate("+ tWidth + "," + tHeight + ")";
Upon resizing you will notice that the words will scramble around. This is something I haven’t had the time to figure out nor, do I see a quick fix for this action on resizing. Maybe someone will piggy back off this solution and figure it out. Until then this is as good as it gets.