Skip to content

Commit 1a2394a

Browse files
committed
Bug fixes + Color by Topic
Fix bugs about floating width/height/size => to remove errors. Color the Terms by its topic (data proccessed is ready for the next display as multiple stream layers instead of one stream)
1 parent e371292 commit 1a2394a

6 files changed

Lines changed: 322 additions & 67 deletions

File tree

d3.layout.wordstream.js

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,46 @@ d3.layout.wordStream = function(){
1919
cw = 1 << 11,
2020
ch = 1 << 11;
2121
wordStream.boxes = function(){
22-
//#region sacle for the font size.
22+
var boxes = buildBoxes(data);
23+
//Can remove data since we've got the boxes.
24+
delete data;
25+
//Get the sprite for each word
26+
getImageData(boxes);
27+
//#endregion boxes information
28+
//Place
29+
var board = buildBoard(boxes);
30+
for(var bc = 0; bc < boxes.length; bc++){
31+
var box = boxes[bc];
32+
var words = box.words;
33+
var n = words.length;
34+
board.boxWidth = box.width;
35+
board.boxHeight = box.height;
36+
board.boxX = box.x;
37+
board.boxY = box.y;
38+
for(var i = 0; i < n; i++){
39+
place(words[i], board);
40+
}
41+
}
42+
43+
//return board;
44+
delete board.sprite;
45+
return boxes;
46+
};
47+
48+
//#region helper functions
49+
//Convert from data to box
50+
function buildBoxes(data){
51+
var start = new Date().getTime();
52+
//Combine terms from each topic
53+
d3.map(data, function(row){
54+
var words = [];
55+
d3.keys(row.words).map(function(topic){
56+
words = words.concat(row.words[topic]);
57+
});
58+
row.words = words;
59+
});
60+
61+
//#region scale for the font size.
2362
var maxFrequency = 0;
2463
var minFrequency = Number.MAX_SAFE_INTEGER;
2564
d3.map(data, function(d){
@@ -45,49 +84,28 @@ d3.layout.wordStream = function(){
4584
d3.map(data, function(d, i){
4685
boxes.push({
4786
width: boxWidth,
48-
height: frequencyScale(totalFrequencies[i]),
87+
height: ~~frequencyScale(totalFrequencies[i]),
4988
x: boxWidth * i,
5089
y: (size[1] - frequencyScale(totalFrequencies[i]))/2,
5190
words: d.words
5291
});
5392
});
54-
55-
//Get the sprite for each word
56-
getImageData(boxes);
57-
//#endregion boxes information
58-
//Place
59-
var board = buildBoard(boxes);
60-
for(var bc = 0; bc < boxes.length; bc++){
61-
var box = boxes[bc];
62-
var words = box.words;
63-
var n = words.length;
64-
board.boxWidth = box.width;
65-
board.boxHeight = box.height;
66-
board.boxX = box.x;
67-
board.boxY = box.y;
68-
for(var i = 0; i < n; i++){
69-
place(words[i], board);
70-
}
71-
}
72-
//return board;
73-
delete board.sprite;
7493
return boxes;
75-
};
76-
77-
//#region helper functions
94+
}
7895
function place(word, board){
7996
var bw = board.width,
8097
bh = board.height,
8198
maxDelta = ~~Math.sqrt((board.boxWidth*board.boxWidth) + (board.boxHeight*board.boxHeight)),
82-
startX = board.boxX + (board.boxWidth*( Math.random() + .5) >> 1),
83-
startY = board.boxY + (board.boxHeight*( Math.random() + .5) >> 1),
99+
startX = ~~(board.boxX + (board.boxWidth*( Math.random() + .5) >> 1)),
100+
startY = ~~(board.boxY + (board.boxHeight*( Math.random() + .5) >> 1)),
84101
s = spiral([board.boxWidth, board.boxHeight]),
85102
dt = Math.random() < .5 ? 1 : -1,
86103
t = -dt,
87104
dxdy, dx, dy;
88105
word.x = startX;
89106
word.y = startY;
90107
word.placed = false;
108+
var counter = 0;
91109
while (dxdy = s(t += dt)) {
92110
dx = ~~dxdy[0];
93111
dy = ~~dxdy[1];
@@ -100,9 +118,9 @@ d3.layout.wordStream = function(){
100118

101119
if (word.x + word.x0 < 0 || word.y + word.y0 < 0 || word.x + word.x1 > size[0] || word.y + word.y1 > size[1])
102120
continue;
103-
104121
if(!cloudCollide(word, board)){
105122
placeWordToBoard(word, board);
123+
counter++
106124
word.placed = true;
107125
delete word.sprite;
108126
break;
@@ -270,7 +288,7 @@ d3.layout.wordStream = function(){
270288
d = words[di];
271289

272290
c.save();
273-
d.fontSize = fontScale(d.frequency);
291+
d.fontSize = ~~fontScale(d.frequency);
274292
d.rotate = (~~(Math.random() * 6) - 3) * 30;
275293
c.font = ~~(d.fontSize + 1) + "px " + font;
276294

@@ -380,6 +398,7 @@ d3.layout.wordStream = function(){
380398
wordStream.buildCanvas = buildCanvas;
381399
wordStream.buildBoard = buildBoard;
382400
wordStream.placeWordToBoard = placeWordToBoard;
401+
wordStream.buildBoxes = buildBoxes;
383402
//#endregion
384403
//Exporting the functions to set configuration data
385404
//#region setter/getter functions

test/emptywheel.csv

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

test/finalboard.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
6+
<title>WordStream</title>
7+
<script src="../d3.min.js"></script>
8+
<script src="../d3.layout.wordstream.js"></script>
9+
<script src="./testutil.js"></script>
10+
</head>
11+
<body>
12+
<script>
13+
var url = "./emptywheel.csv";
14+
d3.csv(url, function(error, rawData) {
15+
if (error) throw error;
16+
var inputFormat = d3.time.format('%Y-%m-%dT%H:%M:%S');
17+
var outputFormat = d3.time.format('%b %Y');
18+
var topics = d3.keys(rawData[0]).slice(2, 6);
19+
//Filter and take only dates in 2013
20+
rawData = rawData.filter(function(d){
21+
var time = inputFormat.parse(d.time);
22+
var starDate = inputFormat.parse('2013-01-01T00:00:00');
23+
var endDate = inputFormat.parse('2014-01-01T00:00:00');
24+
return time >= starDate && time < endDate;
25+
});
26+
27+
var data = {};
28+
d3.map(rawData, function(d, i){
29+
var date = inputFormat.parse(d.time);
30+
var date = outputFormat(date);
31+
topics.forEach(topic => {
32+
if(!data[date]) data[date] = {};
33+
data[date][topic] += data[date][topic] ? ('|' +d[topic]): (d[topic]);
34+
});
35+
});
36+
var data = d3.keys(data).map(function(date, i){
37+
var words = {};
38+
topics.forEach(topic => {
39+
var raw = {};
40+
raw[topic] = data[date][topic].split('|');
41+
//Count word frequencies
42+
var counts = raw[topic].reduce(function(obj, word){
43+
if(!obj[word]){
44+
obj[word] = 0;
45+
}
46+
obj[word]++;
47+
return obj;
48+
}, {});
49+
//Convert to array of objects
50+
words[topic] = d3.keys(counts).map(function(d){
51+
return{
52+
text: d,
53+
frequency: counts[d],
54+
topic: topic
55+
}
56+
}).sort(function(a, b){//sort the terms by frequency
57+
return b.frequency-a.frequency;
58+
}).filter(function(d){return d.text; })//filter out empty words
59+
.slice(0, 5);
60+
});
61+
return {
62+
date: date,
63+
words: words
64+
}
65+
}).sort(function(a, b){//sort by date
66+
return outputFormat.parse(a.date) - outputFormat.parse(b.date);
67+
});
68+
draw(data);
69+
});
70+
function draw(data){
71+
var ws = d3.layout.wordStream()
72+
.data(data);
73+
74+
var board = ws.boxes();
75+
76+
var cw = 1 << 11,
77+
ch = 1 << 11;
78+
var canvas = d3.select('body').append("canvas").attr({
79+
width: cw,
80+
height: ch,
81+
}).style('border', '1px solid black');
82+
var c = canvas[0][0].getContext("2d");
83+
spriteToScreen(c, board);
84+
};
85+
</script>
86+
</body>
87+
</html>

test/sprite.html

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
6+
<title>WordStream</title>
7+
<script src="../d3.min.js"></script>
8+
<script src="../d3.layout.wordstream.js"></script>
9+
</head>
10+
<body>
11+
<script>
12+
var url = "./emptywheel.csv";
13+
d3.csv(url, function(error, rawData) {
14+
if (error) throw error;
15+
var inputFormat = d3.time.format('%Y-%m-%dT%H:%M:%S');
16+
var outputFormat = d3.time.format('%b %Y');
17+
var topics = d3.keys(rawData[0]).slice(2, 6);
18+
//Filter and take only dates in 2013
19+
rawData = rawData.filter(function(d){
20+
var time = inputFormat.parse(d.time);
21+
var starDate = inputFormat.parse('2013-01-01T00:00:00');
22+
var endDate = inputFormat.parse('2014-01-01T00:00:00');
23+
return time >= starDate && time < endDate;
24+
});
25+
26+
var data = {};
27+
d3.map(rawData, function(d, i){
28+
var date = inputFormat.parse(d.time);
29+
var date = outputFormat(date);
30+
topics.forEach(topic => {
31+
if(!data[date]) data[date] = {};
32+
data[date][topic] += data[date][topic] ? ('|' +d[topic]): (d[topic]);
33+
});
34+
});
35+
var data = d3.keys(data).map(function(date, i){
36+
var words = {};
37+
topics.forEach(topic => {
38+
var raw = {};
39+
raw[topic] = data[date][topic].split('|');
40+
//Count word frequencies
41+
var counts = raw[topic].reduce(function(obj, word){
42+
if(!obj[word]){
43+
obj[word] = 0;
44+
}
45+
obj[word]++;
46+
return obj;
47+
}, {});
48+
//Convert to array of objects
49+
words[topic] = d3.keys(counts).map(function(d){
50+
return{
51+
text: d,
52+
frequency: counts[d],
53+
topic: topic
54+
}
55+
}).sort(function(a, b){//sort the terms by frequency
56+
return b.frequency-a.frequency;
57+
}).filter(function(d){return d.text; })//filter out empty words
58+
.slice(0, 5);
59+
});
60+
return {
61+
date: date,
62+
words: words
63+
}
64+
}).sort(function(a, b){//sort by date
65+
return outputFormat.parse(a.date) - outputFormat.parse(b.date);
66+
});
67+
draw(data);
68+
});
69+
function draw(data){
70+
var ws = d3.layout.wordStream()
71+
.data(data)
72+
.minFontSize(6)
73+
.maxFontSize(24);
74+
//var boxes = ws.boxes();
75+
var cw = 1 << 11,
76+
ch = 1 << 11;
77+
var canvas = d3.select('body').append("canvas").attr({
78+
width: cw,
79+
height: ch,
80+
}).style('border', '1px solid black');
81+
var c = canvas[0][0].getContext("2d");
82+
var boxes = ws.buildBoxes(data);
83+
var imageData = ws.getImageData(boxes);
84+
c.putImageData(imageData, 0, 0);
85+
//Draw the boxes to see the x and y and width, height coordinate is right or not
86+
for(var bc =0; bc< boxes.length; bc++){
87+
var words = boxes[bc].words;
88+
for(var i =0; i< words.length; i++){
89+
var word = words[i];
90+
c.rect(word.x, word.y, word.width, word.height);
91+
}
92+
}
93+
c.stroke();
94+
};
95+
</script>
96+
</body>
97+
</html>

test/testutil.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
function spriteToScreen(c, word){
2+
var imageData = c.getImageData(word.x, word.y, word.width, word.height);
3+
for(var i=0; i<<2 < imageData.data.length; i++){
4+
if(word.sprite[i]!=0){
5+
imageData.data[i<<2] = word.sprite[i];
6+
imageData.data[(i<<2)+1] = 0;
7+
imageData.data[(i<<2)+2] = 0;
8+
//Set alpha to 1
9+
imageData.data[(i<<2)+3] = 255;
10+
}
11+
}
12+
c.putImageData(imageData, word.x, word.y);
13+
}
14+
function buildSprite(width, height){
15+
var canvas = document.createElement('canvas');
16+
canvas.width = width;
17+
canvas.height = height;
18+
var c = canvas.getContext("2d");
19+
c.fillStyle = 'red';
20+
c.fillRect(0, 0, width, height);
21+
var pixels = c.getImageData(0, 0, width, height).data;
22+
var sprite = [];
23+
for(var i =0; i < width*height; i++){
24+
sprite[i] = 0;
25+
}
26+
for(var i = 0; i< width*height; i++){
27+
sprite[i] = pixels[i<<2];
28+
}
29+
return sprite;
30+
}

0 commit comments

Comments
 (0)