Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
82f87a91
Commit
82f87a91
authored
Apr 09, 2013
by
Valera Rozuvan
Committed by
Vasyl Nakvasiuk
May 13, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added rough version of d3 word cloud.
parent
acfbe14e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
478 additions
and
3 deletions
+478
-3
common/lib/xmodule/xmodule/js/src/word_cloud/d3.layout.cloud.js
+404
-0
common/lib/xmodule/xmodule/js/src/word_cloud/d3.min.js
+0
-0
common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js
+72
-3
common/lib/xmodule/xmodule/word_cloud_module.py
+2
-0
No files found.
common/lib/xmodule/xmodule/js/src/word_cloud/d3.layout.cloud.js
0 → 100644
View file @
82f87a91
// Word cloud layout by Jason Davies, http://www.jasondavies.com/word-cloud/
// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
(
function
(
exports
)
{
function
cloud
()
{
var
size
=
[
256
,
256
],
text
=
cloudText
,
font
=
cloudFont
,
fontSize
=
cloudFontSize
,
fontStyle
=
cloudFontNormal
,
fontWeight
=
cloudFontNormal
,
rotate
=
cloudRotate
,
padding
=
cloudPadding
,
spiral
=
archimedeanSpiral
,
words
=
[],
timeInterval
=
Infinity
,
event
=
d3
.
dispatch
(
"word"
,
"end"
),
timer
=
null
,
cloud
=
{};
cloud
.
start
=
function
()
{
var
board
=
zeroArray
((
size
[
0
]
>>
5
)
*
size
[
1
]),
bounds
=
null
,
n
=
words
.
length
,
i
=
-
1
,
tags
=
[],
data
=
words
.
map
(
function
(
d
,
i
)
{
d
.
text
=
text
.
call
(
this
,
d
,
i
);
d
.
font
=
font
.
call
(
this
,
d
,
i
);
d
.
style
=
fontStyle
.
call
(
this
,
d
,
i
);
d
.
weight
=
fontWeight
.
call
(
this
,
d
,
i
);
d
.
rotate
=
rotate
.
call
(
this
,
d
,
i
);
d
.
size
=
~~
fontSize
.
call
(
this
,
d
,
i
);
d
.
padding
=
cloudPadding
.
call
(
this
,
d
,
i
);
return
d
;
}).
sort
(
function
(
a
,
b
)
{
return
b
.
size
-
a
.
size
;
});
if
(
timer
)
clearInterval
(
timer
);
timer
=
setInterval
(
step
,
0
);
step
();
return
cloud
;
function
step
()
{
var
start
=
+
new
Date
,
d
;
while
(
+
new
Date
-
start
<
timeInterval
&&
++
i
<
n
&&
timer
)
{
d
=
data
[
i
];
d
.
x
=
(
size
[
0
]
*
(
Math
.
random
()
+
.
5
))
>>
1
;
d
.
y
=
(
size
[
1
]
*
(
Math
.
random
()
+
.
5
))
>>
1
;
cloudSprite
(
d
,
data
,
i
);
if
(
place
(
board
,
d
,
bounds
))
{
tags
.
push
(
d
);
event
.
word
(
d
);
if
(
bounds
)
cloudBounds
(
bounds
,
d
);
else
bounds
=
[{
x
:
d
.
x
+
d
.
x0
,
y
:
d
.
y
+
d
.
y0
},
{
x
:
d
.
x
+
d
.
x1
,
y
:
d
.
y
+
d
.
y1
}];
// Temporary hack
d
.
x
-=
size
[
0
]
>>
1
;
d
.
y
-=
size
[
1
]
>>
1
;
}
}
if
(
i
>=
n
)
{
cloud
.
stop
();
event
.
end
(
tags
,
bounds
);
}
}
}
cloud
.
stop
=
function
()
{
if
(
timer
)
{
clearInterval
(
timer
);
timer
=
null
;
}
return
cloud
;
};
cloud
.
timeInterval
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
timeInterval
;
timeInterval
=
x
==
null
?
Infinity
:
x
;
return
cloud
;
};
function
place
(
board
,
tag
,
bounds
)
{
var
perimeter
=
[{
x
:
0
,
y
:
0
},
{
x
:
size
[
0
],
y
:
size
[
1
]}],
startX
=
tag
.
x
,
startY
=
tag
.
y
,
maxDelta
=
Math
.
sqrt
(
size
[
0
]
*
size
[
0
]
+
size
[
1
]
*
size
[
1
]),
s
=
spiral
(
size
),
dt
=
Math
.
random
()
<
.
5
?
1
:
-
1
,
t
=
-
dt
,
dxdy
,
dx
,
dy
;
while
(
dxdy
=
s
(
t
+=
dt
))
{
dx
=
~~
dxdy
[
0
];
dy
=
~~
dxdy
[
1
];
if
(
Math
.
min
(
dx
,
dy
)
>
maxDelta
)
break
;
tag
.
x
=
startX
+
dx
;
tag
.
y
=
startY
+
dy
;
if
(
tag
.
x
+
tag
.
x0
<
0
||
tag
.
y
+
tag
.
y0
<
0
||
tag
.
x
+
tag
.
x1
>
size
[
0
]
||
tag
.
y
+
tag
.
y1
>
size
[
1
])
continue
;
// TODO only check for collisions within current bounds.
if
(
!
bounds
||
!
cloudCollide
(
tag
,
board
,
size
[
0
]))
{
if
(
!
bounds
||
collideRects
(
tag
,
bounds
))
{
var
sprite
=
tag
.
sprite
,
w
=
tag
.
width
>>
5
,
sw
=
size
[
0
]
>>
5
,
lx
=
tag
.
x
-
(
w
<<
4
),
sx
=
lx
&
0x7f
,
msx
=
32
-
sx
,
h
=
tag
.
y1
-
tag
.
y0
,
x
=
(
tag
.
y
+
tag
.
y0
)
*
sw
+
(
lx
>>
5
),
last
;
for
(
var
j
=
0
;
j
<
h
;
j
++
)
{
last
=
0
;
for
(
var
i
=
0
;
i
<=
w
;
i
++
)
{
board
[
x
+
i
]
|=
(
last
<<
msx
)
|
(
i
<
w
?
(
last
=
sprite
[
j
*
w
+
i
])
>>>
sx
:
0
);
}
x
+=
sw
;
}
delete
tag
.
sprite
;
return
true
;
}
}
}
return
false
;
}
cloud
.
words
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
words
;
words
=
x
;
return
cloud
;
};
cloud
.
size
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
size
;
size
=
[
+
x
[
0
],
+
x
[
1
]];
return
cloud
;
};
cloud
.
font
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
font
;
font
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
fontStyle
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
fontStyle
;
fontStyle
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
fontWeight
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
fontWeight
;
fontWeight
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
rotate
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
rotate
;
rotate
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
text
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
text
;
text
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
spiral
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
spiral
;
spiral
=
spirals
[
x
+
""
]
||
x
;
return
cloud
;
};
cloud
.
fontSize
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
fontSize
;
fontSize
=
d3
.
functor
(
x
);
return
cloud
;
};
cloud
.
padding
=
function
(
x
)
{
if
(
!
arguments
.
length
)
return
padding
;
padding
=
d3
.
functor
(
x
);
return
cloud
;
};
return
d3
.
rebind
(
cloud
,
event
,
"on"
);
}
function
cloudText
(
d
)
{
return
d
.
text
;
}
function
cloudFont
()
{
return
"serif"
;
}
function
cloudFontNormal
()
{
return
"normal"
;
}
function
cloudFontSize
(
d
)
{
return
Math
.
sqrt
(
d
.
value
);
}
function
cloudRotate
()
{
return
(
~~
(
Math
.
random
()
*
6
)
-
3
)
*
30
;
}
function
cloudPadding
()
{
return
1
;
}
// Fetches a monochrome sprite bitmap for the specified text.
// Load in batches for speed.
function
cloudSprite
(
d
,
data
,
di
)
{
if
(
d
.
sprite
)
return
;
c
.
clearRect
(
0
,
0
,
(
cw
<<
5
)
/
ratio
,
ch
/
ratio
);
var
x
=
0
,
y
=
0
,
maxh
=
0
,
n
=
data
.
length
;
di
--
;
while
(
++
di
<
n
)
{
d
=
data
[
di
];
c
.
save
();
c
.
font
=
d
.
style
+
" "
+
d
.
weight
+
" "
+
~~
((
d
.
size
+
1
)
/
ratio
)
+
"px "
+
d
.
font
;
var
w
=
c
.
measureText
(
d
.
text
+
"m"
).
width
*
ratio
,
h
=
d
.
size
<<
1
;
if
(
d
.
rotate
)
{
var
sr
=
Math
.
sin
(
d
.
rotate
*
cloudRadians
),
cr
=
Math
.
cos
(
d
.
rotate
*
cloudRadians
),
wcr
=
w
*
cr
,
wsr
=
w
*
sr
,
hcr
=
h
*
cr
,
hsr
=
h
*
sr
;
w
=
(
Math
.
max
(
Math
.
abs
(
wcr
+
hsr
),
Math
.
abs
(
wcr
-
hsr
))
+
0x1f
)
>>
5
<<
5
;
h
=
~~
Math
.
max
(
Math
.
abs
(
wsr
+
hcr
),
Math
.
abs
(
wsr
-
hcr
));
}
else
{
w
=
(
w
+
0x1f
)
>>
5
<<
5
;
}
if
(
h
>
maxh
)
maxh
=
h
;
if
(
x
+
w
>=
(
cw
<<
5
))
{
x
=
0
;
y
+=
maxh
;
maxh
=
0
;
}
if
(
y
+
h
>=
ch
)
break
;
c
.
translate
((
x
+
(
w
>>
1
))
/
ratio
,
(
y
+
(
h
>>
1
))
/
ratio
);
if
(
d
.
rotate
)
c
.
rotate
(
d
.
rotate
*
cloudRadians
);
c
.
fillText
(
d
.
text
,
0
,
0
);
c
.
restore
();
d
.
width
=
w
;
d
.
height
=
h
;
d
.
xoff
=
x
;
d
.
yoff
=
y
;
d
.
x1
=
w
>>
1
;
d
.
y1
=
h
>>
1
;
d
.
x0
=
-
d
.
x1
;
d
.
y0
=
-
d
.
y1
;
x
+=
w
;
}
var
pixels
=
c
.
getImageData
(
0
,
0
,
(
cw
<<
5
)
/
ratio
,
ch
/
ratio
).
data
,
sprite
=
[];
while
(
--
di
>=
0
)
{
d
=
data
[
di
];
var
w
=
d
.
width
,
w32
=
w
>>
5
,
h
=
d
.
y1
-
d
.
y0
,
p
=
d
.
padding
;
// Zero the buffer
for
(
var
i
=
0
;
i
<
h
*
w32
;
i
++
)
sprite
[
i
]
=
0
;
x
=
d
.
xoff
;
if
(
x
==
null
)
return
;
y
=
d
.
yoff
;
var
seen
=
0
,
seenRow
=
-
1
;
for
(
var
j
=
0
;
j
<
h
;
j
++
)
{
for
(
var
i
=
0
;
i
<
w
;
i
++
)
{
var
k
=
w32
*
j
+
(
i
>>
5
),
m
=
pixels
[((
y
+
j
)
*
(
cw
<<
5
)
+
(
x
+
i
))
<<
2
]
?
1
<<
(
31
-
(
i
%
32
))
:
0
;
if
(
p
)
{
if
(
j
)
sprite
[
k
-
w32
]
|=
m
;
if
(
j
<
w
-
1
)
sprite
[
k
+
w32
]
|=
m
;
m
|=
(
m
<<
1
)
|
(
m
>>
1
);
}
sprite
[
k
]
|=
m
;
seen
|=
m
;
}
if
(
seen
)
seenRow
=
j
;
else
{
d
.
y0
++
;
h
--
;
j
--
;
y
++
;
}
}
d
.
y1
=
d
.
y0
+
seenRow
;
d
.
sprite
=
sprite
.
slice
(
0
,
(
d
.
y1
-
d
.
y0
)
*
w32
);
}
}
// Use mask-based collision detection.
function
cloudCollide
(
tag
,
board
,
sw
)
{
sw
>>=
5
;
var
sprite
=
tag
.
sprite
,
w
=
tag
.
width
>>
5
,
lx
=
tag
.
x
-
(
w
<<
4
),
sx
=
lx
&
0x7f
,
msx
=
32
-
sx
,
h
=
tag
.
y1
-
tag
.
y0
,
x
=
(
tag
.
y
+
tag
.
y0
)
*
sw
+
(
lx
>>
5
),
last
;
for
(
var
j
=
0
;
j
<
h
;
j
++
)
{
last
=
0
;
for
(
var
i
=
0
;
i
<=
w
;
i
++
)
{
if
(((
last
<<
msx
)
|
(
i
<
w
?
(
last
=
sprite
[
j
*
w
+
i
])
>>>
sx
:
0
))
&
board
[
x
+
i
])
return
true
;
}
x
+=
sw
;
}
return
false
;
}
function
cloudBounds
(
bounds
,
d
)
{
var
b0
=
bounds
[
0
],
b1
=
bounds
[
1
];
if
(
d
.
x
+
d
.
x0
<
b0
.
x
)
b0
.
x
=
d
.
x
+
d
.
x0
;
if
(
d
.
y
+
d
.
y0
<
b0
.
y
)
b0
.
y
=
d
.
y
+
d
.
y0
;
if
(
d
.
x
+
d
.
x1
>
b1
.
x
)
b1
.
x
=
d
.
x
+
d
.
x1
;
if
(
d
.
y
+
d
.
y1
>
b1
.
y
)
b1
.
y
=
d
.
y
+
d
.
y1
;
}
function
collideRects
(
a
,
b
)
{
return
a
.
x
+
a
.
x1
>
b
[
0
].
x
&&
a
.
x
+
a
.
x0
<
b
[
1
].
x
&&
a
.
y
+
a
.
y1
>
b
[
0
].
y
&&
a
.
y
+
a
.
y0
<
b
[
1
].
y
;
}
function
archimedeanSpiral
(
size
)
{
var
e
=
size
[
0
]
/
size
[
1
];
return
function
(
t
)
{
return
[
e
*
(
t
*=
.
1
)
*
Math
.
cos
(
t
),
t
*
Math
.
sin
(
t
)];
};
}
function
rectangularSpiral
(
size
)
{
var
dy
=
4
,
dx
=
dy
*
size
[
0
]
/
size
[
1
],
x
=
0
,
y
=
0
;
return
function
(
t
)
{
var
sign
=
t
<
0
?
-
1
:
1
;
// See triangular numbers: T_n = n * (n + 1) / 2.
switch
((
Math
.
sqrt
(
1
+
4
*
sign
*
t
)
-
sign
)
&
3
)
{
case
0
:
x
+=
dx
;
break
;
case
1
:
y
+=
dy
;
break
;
case
2
:
x
-=
dx
;
break
;
default
:
y
-=
dy
;
break
;
}
return
[
x
,
y
];
};
}
// TODO reuse arrays?
function
zeroArray
(
n
)
{
var
a
=
[],
i
=
-
1
;
while
(
++
i
<
n
)
a
[
i
]
=
0
;
return
a
;
}
var
cloudRadians
=
Math
.
PI
/
180
,
cw
=
1
<<
11
>>
5
,
ch
=
1
<<
11
,
canvas
,
ratio
=
1
;
if
(
typeof
document
!==
"undefined"
)
{
canvas
=
document
.
createElement
(
"canvas"
);
canvas
.
width
=
1
;
canvas
.
height
=
1
;
ratio
=
Math
.
sqrt
(
canvas
.
getContext
(
"2d"
).
getImageData
(
0
,
0
,
1
,
1
).
data
.
length
>>
2
);
canvas
.
width
=
(
cw
<<
5
)
/
ratio
;
canvas
.
height
=
ch
/
ratio
;
}
else
{
// node-canvas support
var
Canvas
=
require
(
"canvas"
);
canvas
=
new
Canvas
(
cw
<<
5
,
ch
);
}
var
c
=
canvas
.
getContext
(
"2d"
),
spirals
=
{
archimedean
:
archimedeanSpiral
,
rectangular
:
rectangularSpiral
};
c
.
fillStyle
=
"red"
;
c
.
textAlign
=
"center"
;
exports
.
cloud
=
cloud
;
})(
typeof
exports
===
"undefined"
?
d3
.
layout
||
(
d3
.
layout
=
{})
:
exports
);
common/lib/xmodule/xmodule/js/src/word_cloud/d3.min.js
0 → 100644
View file @
82f87a91
This source diff could not be displayed because it is too large. You can
view the blob
instead.
common/lib/xmodule/xmodule/js/src/word_cloud/word_cloud_main.js
View file @
82f87a91
(
function
(
requirejs
,
require
,
define
)
{
define
(
'WordCloudMain'
,
[
'logme'
],
function
(
logme
)
{
var
hash
=
0
;
WordCloudMain
.
prototype
=
{
'submitAnswer'
:
function
()
{
...
...
@@ -36,16 +38,62 @@ WordCloudMain.prototype = {
},
// End-of: 'submitAnswer': function (answer, answerEl) {
'showWordCloud'
:
function
(
response
){
var
words
,
_this
=
this
,
fill
=
d3
.
scale
.
category20
();
console
.
log
(
'Show word cloud with next:'
);
console
.
log
(
response
);
inputSection
=
this
.
wordCloudEl
.
find
(
'#input-cloud-section'
);
resultSection
=
this
.
wordCloudEl
.
find
(
'#result-cloud-section'
);
resultSection
.
text
(
'TODO: Word cloud canvas'
);
inputSection
.
hide
();
resultSection
.
show
();
},
words
=
response
.
top_words
;
d3
.
layout
.
cloud
().
size
([
5
,
5
])
.
words
(
words
)
.
rotate
(
function
()
{
return
~~
(
Math
.
random
()
*
2
)
*
90
;
})
.
font
(
'Impact'
)
.
fontSize
(
function
(
d
)
{
return
d
.
size
;
})
.
on
(
'end'
,
draw
)
.
start
();
// End of executable code.
return
;
function
draw
(
words
)
{
d3
.
select
(
'.word_cloud_d3_'
+
_this
.
hash
).
append
(
'svg'
)
.
attr
(
'width'
,
500
)
.
attr
(
'height'
,
500
)
.
append
(
'g'
)
// .attr('transform', 'translate(125,125)')
.
selectAll
(
'text'
)
.
data
(
words
)
.
enter
().
append
(
'text'
)
.
style
(
'font-size'
,
function
(
d
)
{
return
d
.
size
+
'px'
;
})
.
style
(
'font-family'
,
'Impact'
)
.
style
(
'fill'
,
function
(
d
,
i
)
{
return
fill
(
i
);
})
.
attr
(
'text-anchor'
,
'middle'
)
.
attr
(
'transform'
,
function
(
d
)
{
return
'translate('
+
[
d
.
x
,
d
.
y
]
+
')rotate('
+
d
.
rotate
+
')'
;
})
.
text
(
function
(
d
)
{
return
d
.
text
;
});
}
}
};
// End-of: WordCloudMain.prototype = {
...
...
@@ -53,6 +101,7 @@ return WordCloudMain;
function
WordCloudMain
(
el
)
{
var
_this
;
this
.
wordCloudEl
=
$
(
el
).
find
(
'.word_cloud'
);
if
(
this
.
wordCloudEl
.
length
!==
1
)
{
// We require one question DOM element.
...
...
@@ -61,6 +110,26 @@ function WordCloudMain(el) {
return
;
}
hash
+=
1
;
this
.
hash
=
hash
;
this
.
wordCloudEl
.
addClass
(
'word_cloud_d3_'
+
this
.
hash
);
this
.
configJson
=
null
;
try
{
this
.
configJson
=
JSON
.
parse
(
this
.
wordCloudEl
.
find
(
'.word_cloud_div'
).
html
());
}
catch
(
err
)
{
logme
(
'ERROR: Incorrect JSON config was given.'
);
logme
(
err
.
message
);
return
;
}
if
(
this
.
configJson
.
hasOwnProperty
(
'status'
)
&&
this
.
configJson
.
status
===
'success'
)
{
this
.
showWordCloud
(
this
.
configJson
);
return
;
}
this
.
inputSaveEl
=
$
(
el
).
find
(
'input.save'
);
// Get the URL to which we will post the users words.
...
...
common/lib/xmodule/xmodule/word_cloud_module.py
View file @
82f87a91
...
...
@@ -44,6 +44,8 @@ class WordCloudModule(WordCloudFields, XModule):
js
=
{
'coffee'
:
[
resource_string
(
__name__
,
'js/src/javascript_loader.coffee'
)],
'js'
:
[
resource_string
(
__name__
,
'js/src/word_cloud/logme.js'
),
resource_string
(
__name__
,
'js/src/word_cloud/d3.min.js'
),
resource_string
(
__name__
,
'js/src/word_cloud/d3.layout.cloud.js'
),
resource_string
(
__name__
,
'js/src/word_cloud/word_cloud.js'
),
resource_string
(
__name__
,
'js/src/word_cloud/word_cloud_main.js'
)]
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment