Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F62482475
index.html
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, May 13, 12:39
Size
19 KB
Mime Type
text/html
Expires
Wed, May 15, 12:39 (2 d)
Engine
blob
Format
Raw Data
Handle
17652175
Attached To
R1473 warcbase
index.html
View Options
<!DOCTYPE html>
<html>
<meta
charset=
"utf-8"
>
<!--
This visualization was inspired by the Location Cloud from the Trading Consequences
Project (http://tcqdev.edina.ac.uk/vis/locationCloud/index.php?com=Sugar), but it
was written from scratch.
Ideas for future improvements/features:
- Use SVG for frequency lists, following Location Cloud example, for more control
over layout?
- Normalize list item font sizes, so each list is same height.
- More visualizations.
- Option to save graphic visualizations as image. (See http://techslides.com/save-svg-as-an-image.)
- Offer embed codes.
- Option to upload data file into app.
-->
<link
rel=
"stylesheet"
href=
"//yui.yahooapis.com/pure/0.6.0/pure-min.css"
>
<link
rel=
"stylesheet"
href=
"//cdnjs.cloudflare.com/ajax/libs/noUiSlider/8.0.2/nouislider.min.css"
>
<style>
body
{
font-family
:
"Helvetica Neue"
,
Helvetica
,
sans-serif
;
margin
:
2
%
;
}
.entitylist
{
list-style-type
:
none
;
padding
:
0
;
margin
:
0
;
text-align
:
center
;
}
#no-parameters
{
display
:
none
;
padding
:
0
10
%
;
}
#data-select
{
display
:
none
;
}
#list-window
{
margin-top
:
0.5em
;
overflow-x
:
scroll
;
text-align
:
center
;
}
#list-table
{
margin
:
0
auto
;
text-align
:
center
;
}
#list-table
td
{
vertical-align
:
top
;
}
#list-table
ul
li
{
white-space
:
nowrap
;
max-width
:
25em
;
overflow
:
hidden
;
}
#list-row
h1
{
font-size
:
12px
;
font-weight
:
400
;
background
:
lightgray
;
padding
:
3px
;
margin
:
3px
;
display
:
inline
;
}
#data-select
{
text-align
:
center
;
}
#data-select
button
{
color
:
white
;
}
#data-select
form
{
margin-top
:
1em
;
}
.pure-button-active
{
background
:
rgb
(
66
,
184
,
221
);
}
.word-cloud
{
margin
:
1em
auto
;
text-align
:
center
;
}
.bubble-wrap
{
margin
:
1em
auto
;
text-align
:
center
;
}
div
.list-tooltip
{
position
:
absolute
;
text-align
:
center
;
min-width
:
60px
;
min-height
:
28px
;
padding
:
2px
;
font
:
12px
sans-serif
;
background
:
lightsteelblue
;
border
:
0px
;
border
-
radius
:
8px
;
pointer
-
events
:
none
;
opacity
:
0
;
}
#list-msg
{
padding
:
5px
15px
;
border
-
radius
:
5px
;
background-color
:
lightsteelblue
;
position
:
absolute
;
left
:
50
%
;
top
:
60
%
;
transform
:
translate
(
-50
%,
-50
%
);
opacity
:
0
.
9
;
text-align
:
center
;
font-size
:
large
;
visibility
:
hidden
;
}
#date-range-lower
,
#date-range-upper
{
position
:
relative
;
top
:
-15px
;
display
:
inline
-
block
;
text-align
:
center
;
width
:
5.5em
;
font-size
:
small
;
color
:
darkgray
;
}
#date-range-slider
{
display
:
inline
-
block
;
width
:
25em
;
margin
:
0
auto
1em
auto
;
}
#timescale-label
{
display
:
inline
-
block
;
width
:
3.5em
;
}
.noUi-horizontal
{
height
:
8px
;
}
.noUi-horizontal
.noUi-handle
{
width
:
18px
;
height
:
14px
;
left
:
-10px
;
top
:
-4px
;
}
.noUi-connect
{
background
:
darkgray
;
}
.noUi-handle
:before
,
.noUi-handle
:after
{
height
:
8px
;
width
:
1px
;
left
:
6px
;
top
:
2px
;
}
.noUi-handle
:after
{
left
:
9px
;
}
</style>
<script
src=
"URI.js"
></script>
<script
src=
"//d3js.org/d3.v3.min.js"
></script>
<script
src=
"//cdnjs.cloudflare.com/ajax/libs/noUiSlider/8.0.2/nouislider.min.js"
></script>
<script
src=
"d3.layout.cloud.js"
></script>
<body>
<h1>
Named Entity Visualization
</h1>
<p
id=
"json-source"
></p>
<div
id=
"data-select"
>
<button
id=
"PERSONButt"
class=
"pure-button"
onclick=
"updateEntityType('PERSON')"
>
Persons
</button><button
id=
"ORGANIZATIONButt"
class=
"pure-button"
onclick=
"updateEntityType('ORGANIZATION')"
>
Organizations
</button><button
id=
"LOCATIONButt"
class=
"pure-button"
onclick=
"updateEntityType('LOCATION')"
>
Locations
</button>
<form
class=
"pure-form pure-form-stacked"
>
<label
for=
"timescale-range"
>
Time scale:
<span
id=
"timescale-label"
></span></label>
<input
type=
"range"
name=
"timescale-range"
id=
"timescale-range"
onchange=
"updateTimescale(this.value)"
oninput=
"setTimescaleText(this.value)"
min=
"0"
max=
"3"
value=
"0"
>
<label
for=
"date-range"
>
Date range
</label>
</form>
<div
id=
"date-range-wrap"
>
<div
id=
"date-range-lower"
></div>
<div
id=
"date-range-slider"
></div>
<div
id=
"date-range-upper"
></div>
</div>
</div>
<div
id=
"no-parameters"
>
<p>
You must specify the data set you wish to visualize by passing the filename (located on
this server) as a parameter, e.g.,
<i><script>
document
.
write
(
location
.
href
.
split
(
"?"
)[
0
])
</script><b>
index.html?json=fileName.json
</b></i>
.
</p>
<p>
Try
<script>
document
.
write
(
"<a href='"
+
location
.
href
.
split
(
"?"
)[
0
]
+
"index.html?json=greenparty.json'>"
)
</script>
this example
</a>
.
</p>
</div>
<div
id=
"list-window"
>
<span
id=
"list-msg"
>
Loading
</span>
<table
id=
"list-table"
><tr
id=
"list-row"
></tr></table>
</div>
<div
class=
"list-tooltip"
></div>
<script>
var
entityType
=
null
;
var
allData
=
null
;
var
nestedData
=
null
;
var
fill
=
d3
.
scale
.
category20
();
var
listTooltip
=
null
;
var
timeScale
=
"0"
;
var
firstOverflow
=
true
;
function
init
()
{
var
jsonFile
=
new
URI
().
search
(
true
).
json
;
setTimescaleText
(
timeScale
);
if
(
!
jsonFile
)
{
d3
.
select
(
"#no-parameters"
).
style
(
"display"
,
"block"
);
}
else
{
d3
.
select
(
"#data-select"
).
style
(
"display"
,
"block"
);
d3
.
select
(
"#json-source"
).
html
(
"Data source: <a href='"
+
jsonFile
+
"'>"
+
jsonFile
+
"</a>"
)
d3
.
select
(
"#list-msg"
).
style
(
"opacity"
,
.
9
).
style
(
"visibility"
,
"visible"
);
// Load data
d3
.
json
(
jsonFile
,
function
(
error
,
json
)
{
if
(
error
)
{
d3
.
select
(
"#list-msg"
).
text
(
"Error loading data"
);
throw
error
;
}
else
{
d3
.
select
(
"#list-msg"
).
style
(
"opacity"
,
0
);
allData
=
explodeNerObjs
(
json
);
/** JSON FORMAT:
[{
"date": "200811",
"domain": "greenparty.ca",
"ner": [{
"nerType": "PERSON",
"entities": [{
"entity": "Elizabeth May",
"freq": 4
}, {
"entity": "Stephen Harper",
"freq": 2
}]
}, {
"nerType": "ORGANIZATION",
"entities": [{
"entity": "ABC",
"freq": 5
}, {
"entity": "XYZ",
"freq": 6
}]
}, {
"nerType": "LOCATION",
"entities": [{
"entity": "Winnipeg",
"freq": 7
}, {
"entity": "Toronto",
"freq": 2
}]
}]
}, {
"date": "200911",
"domain": "greenparty.ca",
"ner": [{
"nerType": "PERSON",
"entities": [{
"entity": "Geroge May",
"freq": 4
}, {
"entity": "Laureen Harper",
"freq": 2
}]
}, {
"nerType": "ORGANIZATION",
"entities": [{
"entity": "Green Party",
"freq": 5
}, {
"entity": "Red Party",
"freq": 6
}]
}, {
"nerType": "LOCATION",
"entities": [{
"entity": "Ajax",
"freq": 7
}, {
"entity": "Yellowknife",
"freq": 2
}]
}]
}]
*/
// Prepare and create date range slider
// Get all months
var
months
=
d3
.
keys
(
d3
.
nest
().
key
(
function
(
d
)
{
return
d
.
date
;
}).
map
(
allData
)).
map
(
function
(
d
)
{
return
parseInt
(
d
)});
var
sliderRange
=
{}
var
minDate
=
d3
.
min
(
months
);
var
maxDate
=
d3
.
max
(
months
);
// Convert months to percentage locations on slider
for
(
i
=
0
;
i
<
months
.
length
;
i
++
)
{
var
pct
;
if
(
i
===
0
)
{
sliderRange
[
'min'
]
=
months
[
i
];
}
else
if
(
i
===
(
months
.
length
-
1
))
{
sliderRange
[
'max'
]
=
months
[
i
];
}
else
{
pct
=
parseFloat
((
months
[
i
]
-
minDate
)
/
(
maxDate
-
minDate
)
*
100
).
toFixed
(
2
);
// 2 decimal places
sliderRange
[
pct
+
'%'
]
=
months
[
i
];
}
}
// Create slider
var
slider
=
d3
.
select
(
"#date-range-slider"
).
node
();
noUiSlider
.
create
(
slider
,
{
range
:
sliderRange
,
snap
:
true
,
connect
:
true
,
start
:
[
minDate
,
maxDate
],
format
:
{
// Otherwise uses default float format
to
:
function
(
v
)
{
return
v
;
},
from
:
function
(
v
)
{
return
v
;
}
}
});
var
snapValues
=
[
d3
.
select
(
'#date-range-lower'
).
node
(),
d3
.
select
(
'#date-range-upper'
).
node
()
];
slider
.
noUiSlider
.
on
(
'update'
,
function
(
values
,
handle
)
{
snapValues
[
handle
].
innerHTML
=
values
[
handle
];
});
slider
.
noUiSlider
.
on
(
'change'
,
function
(
values
)
{
nestedData
=
nestData
(
allData
,
timeScale
);
visualize
(
entityType
,
timeScale
);
});
// Prepare data
nestedData
=
nestData
(
allData
,
timeScale
);
// Do initial visualization
updateEntityType
(
"PERSON"
);
// calls visualize()
}
});
}
}
function
explodeNerObjs
(
data
)
{
var
exploded
=
[]
data
.
forEach
(
function
(
d
)
{
d
.
ner
.
forEach
(
function
(
e
)
{
e
.
entities
.
forEach
(
function
(
f
)
{
exploded
.
push
({
"date"
:
d
.
date
,
"domain"
:
d
.
domain
,
"nerType"
:
e
.
nerType
,
"entity"
:
f
.
entity
,
"freq"
:
f
.
freq
});
})
})
})
return
exploded
;
}
function
nestData
(
data
,
view
)
{
// Returns nestedData[entityType][date] for given view (all-time, year, or month).
// For list and word-cloud visualizations, this could be done more efficiently
// (roughly 3x) by processing only the selected entity-type, but other visualizations
// (e.g. bubbles) need data for all entity types. (Current none require data for
// multiple timescale views.)
var
slider
=
d3
.
select
(
"#date-range-slider"
).
node
();
var
dateRange
=
slider
.
noUiSlider
.
get
();
var
filtered
=
data
.
filter
(
function
(
d
)
{
return
parseInt
(
d
.
date
)
>=
dateRange
[
0
]
&&
parseInt
(
d
.
date
)
<=
dateRange
[
1
]
});
var
eTypes
=
[
"PERSON"
,
"ORGANIZATION"
,
"LOCATION"
];
var
nd
=
{};
var
nestedView
=
d3
.
nest
().
key
(
function
(
d
)
{
return
d
.
nerType
});
if
(
view
===
"0"
)
{
// All-time view
nestedView
=
nestedView
.
map
(
filtered
);
eTypes
.
forEach
(
function
(
item
,
index
)
{
nd
[
item
]
=
{
"all time"
:
summarize
(
nestedView
[
item
])}
});
}
else
if
(
view
===
"1"
)
{
// Year view
nestedView
=
nestedView
.
key
(
function
(
d
)
{
return
d
.
date
.
substring
(
0
,
4
)
})
.
map
(
filtered
);
eTypes
.
forEach
(
function
(
eType
,
eIndex
)
{
nd
[
eType
]
=
{};
Object
.
keys
(
nestedView
[
eType
]).
forEach
(
function
(
year
,
yIndex
)
{
nd
[
eType
][
year
]
=
summarize
(
nestedView
[
eType
][
year
]);
});
});
}
else
if
(
view
===
"2"
)
{
// Month view
nestedView
=
nestedView
.
key
(
function
(
d
)
{
return
d
.
date
.
substring
(
0
,
6
)
})
.
map
(
filtered
);
eTypes
.
forEach
(
function
(
eType
,
eIndex
)
{
nd
[
eType
]
=
{};
Object
.
keys
(
nestedView
[
eType
]).
forEach
(
function
(
yearMonth
,
yIndex
)
{
nd
[
eType
][
yearMonth
]
=
summarize
(
nestedView
[
eType
][
yearMonth
]);
});
});
}
else
if
(
view
===
"3"
)
{
// Day view
nestedView
=
nestedView
.
key
(
function
(
d
)
{
return
d
.
date
})
.
map
(
filtered
);
eTypes
.
forEach
(
function
(
eType
,
eIndex
)
{
nd
[
eType
]
=
{};
Object
.
keys
(
nestedView
[
eType
]).
forEach
(
function
(
yearMonth
,
yIndex
)
{
nd
[
eType
][
yearMonth
]
=
summarize
(
nestedView
[
eType
][
yearMonth
]);
});
});
}
return
nd
;
}
function
summarize
(
entityMap
)
{
var
summary
=
d3
.
nest
().
key
(
function
(
d
){
return
d
.
entity
}).
sortKeys
(
d3
.
ascending
)
.
rollup
(
function
(
d
)
{
return
d3
.
sum
(
d
,
function
(
e
){
return
e
.
freq
})})
.
entries
(
entityMap
);
return
summary
.
sort
(
function
(
a
,
b
)
{
return
b
.
values
-
a
.
values
}
);
}
function
visualize
(
entityType
)
{
// Display lists, including buttons for other visualizations
d3
.
selectAll
(
".word-cloud"
).
remove
();
d3
.
selectAll
(
".bubble-wrap"
).
remove
();
d3
.
select
(
"#list-row"
).
selectAll
(
"td"
).
remove
();
Object
.
keys
(
nestedData
[
entityType
]).
forEach
(
function
(
t
)
{
listify
(
nestedData
[
entityType
][
t
],
t
);
});
var
listWindow
=
d3
.
select
(
"#list-window"
).
node
();
if
(
firstOverflow
&&
listWindow
.
scrollWidth
>
listWindow
.
clientWidth
)
{
firstOverflow
=
false
;
var
infoMsg
=
d3
.
select
(
"#list-msg"
).
html
(
"Scroll ➜"
);
infoMsg
.
style
(
"left"
,
"80%"
)
infoMsg
.
transition
().
duration
(
100
).
style
(
"opacity"
,
.
9
).
transition
().
duration
(
2500
).
style
(
"opacity"
,
0
);
}
}
function
listify
(
data
,
title
)
{
// Generate single list.
// title must correspond to date subset in data (e.g., "all time", "2009", "200510")
var
maxFontSize
=
28
;
var
minFontSize
=
4
;
var
maxItems
=
50
;
// max list size (i.e. top N values, by freq); set to data.size for all
var
maxItemLength
=
20
;
var
labelScale
=
d3
.
scale
.
log
()
//.domain(d3.extent(data, function(d) { return d.freq }))
.
domain
(
d3
.
extent
(
data
,
function
(
d
)
{
return
d
.
values
}))
.
range
([
minFontSize
,
maxFontSize
]);
var
sortedSliced
=
data
.
slice
(
0
,
maxItems
).
sort
(
function
(
a
,
b
)
{
if
(
a
.
key
>
b
.
key
)
// key = entity
return
1
;
if
(
a
.
key
<
b
.
key
)
return
-
1
;
return
0
;
});
var
list
=
d3
.
select
(
"#list-row"
).
append
(
"td"
);
list
.
append
(
"h1"
).
text
(
title
);
list
.
append
(
"ul"
).
attr
(
"class"
,
"entitylist"
).
selectAll
(
"li"
)
.
data
(
sortedSliced
)
.
enter
().
append
(
"li"
)
.
style
(
"font-size"
,
function
(
d
)
{
return
Math
.
round
(
labelScale
(
parseFloat
(
d
.
values
)))
+
"px"
})
.
text
(
function
(
d
)
{
var
s
=
(
d
.
key
.
length
>
maxItemLength
)
?
d
.
key
.
substr
(
0
,
20
)
+
"..."
:
d
.
key
;
return
s
})
.
on
(
"mouseover"
,
function
(
d
)
{
// See http://bl.ocks.org/d3noob/a22c42db65eb00d4e369
listTooltip
=
d3
.
selectAll
(
"div.list-tooltip"
);
listTooltip
.
transition
()
.
duration
(
200
)
.
style
(
"opacity"
,
.
9
);
listTooltip
.
html
(
"<b>"
+
d
.
key
+
"</b><br /> "
+
d
.
values
+
" mentions"
)
.
style
(
"left"
,
(
d3
.
event
.
pageX
)
+
"px"
)
.
style
(
"top"
,
(
d3
.
event
.
pageY
-
28
)
+
"px"
);
})
.
on
(
"mouseout"
,
function
(
d
)
{
listTooltip
.
transition
()
.
duration
(
500
)
.
style
(
"opacity"
,
0
);
});
// Add word cloud button
list
.
append
(
"button"
).
classed
(
"pure-button"
,
"true"
).
attr
(
"onclick"
,
"cloud('"
+
entityType
+
"','"
+
title
+
"')"
).
text
(
"cloud"
);
list
.
append
(
"span"
).
text
(
" "
);
list
.
append
(
"button"
).
classed
(
"pure-button"
,
"true"
).
attr
(
"onclick"
,
"bubble('"
+
title
+
"')"
).
text
(
"bubble"
);
}
function
cloud
(
nerType
,
subsetIdx
)
{
var
maxCloudItems
=
250
;
data
=
nestedData
[
nerType
][
subsetIdx
].
slice
(
0
,
maxCloudItems
);
d3
.
selectAll
(
".word-cloud"
).
remove
();
var
cloudScale
=
d3
.
scale
.
log
()
.
domain
(
d3
.
extent
(
data
,
function
(
d
)
{
return
d
.
values
}))
.
range
([
10
,
100
])
var
layout
=
d3
.
layout
.
cloud
()
.
size
([
1000
,
1000
])
.
words
(
data
.
map
(
function
(
d
)
{
return
{
text
:
d
.
key
,
size
:
Math
.
round
(
cloudScale
(
d
.
values
)),
freq
:
d
.
values
}}))
.
font
(
"Impact"
)
.
fontSize
(
function
(
d
)
{
return
d
.
size
;
})
.
on
(
"end"
,
drawCloud
);
layout
.
start
();
var
e
=
d3
.
selectAll
(
".word-cloud"
).
node
();
e
.
scrollIntoView
();
}
function
drawCloud
(
words
)
{
d3
.
select
(
"body"
).
append
(
"div"
).
classed
(
"word-cloud"
,
true
).
append
(
"svg"
)
.
attr
(
"width"
,
1000
)
.
attr
(
"height"
,
1000
)
.
append
(
"g"
)
.
attr
(
"transform"
,
"translate(500,500)"
)
.
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
;
})
.
on
(
"mouseover"
,
function
(
d
)
{
listTooltip
.
transition
()
.
duration
(
200
)
.
style
(
"opacity"
,
.
9
);
listTooltip
.
html
(
"<b>"
+
d
.
text
+
"</b><br /> "
+
d
.
freq
+
" mentions"
)
.
style
(
"left"
,
(
d3
.
event
.
pageX
)
+
"px"
)
.
style
(
"top"
,
(
d3
.
event
.
pageY
-
28
)
+
"px"
);
})
.
on
(
"mouseout"
,
function
(
d
)
{
listTooltip
.
transition
()
.
duration
(
500
)
.
style
(
"opacity"
,
0
);
});
}
function
bubble
(
subsetIdx
)
{
// Code borrowed from http://bl.ocks.org/mbostock/4063269
var
diameter
=
960
,
format
=
d3
.
format
(
",d"
),
color
=
d3
.
scale
.
category10
();
d3
.
selectAll
(
".bubble-wrap"
).
remove
();
var
bubble
=
d3
.
layout
.
pack
()
.
sort
(
null
)
.
size
([
diameter
,
diameter
])
.
padding
(
1.5
);
var
svg
=
d3
.
select
(
"body"
).
append
(
"div"
).
classed
(
"bubble-wrap"
,
true
).
append
(
"svg"
)
.
attr
(
"width"
,
diameter
)
.
attr
(
"height"
,
diameter
)
.
attr
(
"class"
,
"bubble"
);
var
flatArr
=
flatten
(
nestedData
,
subsetIdx
);
// Randomize array order to avoid concentric rings of same entity type
flatArr
.
sort
(
function
()
{
return
Math
.
random
()
-
.
5
;
});
var
arrObj
=
{
children
:
flatArr
}
var
node
=
svg
.
selectAll
(
".node"
)
.
data
(
bubble
.
nodes
(
arrObj
)
.
filter
(
function
(
d
)
{
return
!
d
.
children
;
}))
.
enter
().
append
(
"g"
)
.
attr
(
"class"
,
"node"
)
.
attr
(
"transform"
,
function
(
d
)
{
return
"translate("
+
d
.
x
+
","
+
d
.
y
+
")"
;
});
node
.
append
(
"circle"
)
.
attr
(
"r"
,
function
(
d
)
{
return
d
.
r
;
})
.
style
(
"fill"
,
function
(
d
)
{
return
color
(
d
.
nerType
);
});
node
.
append
(
"text"
)
.
attr
(
"dy"
,
".3em"
)
.
style
(
"text-anchor"
,
"middle"
)
.
text
(
function
(
d
)
{
return
d
.
entity
.
substring
(
0
,
d
.
r
/
3
);
})
.
on
(
"mouseover"
,
function
(
d
)
{
listTooltip
.
transition
()
.
duration
(
200
)
.
style
(
"opacity"
,
.
9
);
listTooltip
.
html
(
"<b>"
+
d
.
entity
+
"</b><br /> "
+
d
.
value
+
" mentions"
)
.
style
(
"left"
,
(
d3
.
event
.
pageX
)
+
"px"
)
.
style
(
"top"
,
(
d3
.
event
.
pageY
-
28
)
+
"px"
);
})
.
on
(
"mouseout"
,
function
(
d
)
{
listTooltip
.
transition
()
.
duration
(
500
)
.
style
(
"opacity"
,
0
);
});
var
e
=
d3
.
selectAll
(
".bubble"
).
node
();
e
.
scrollIntoView
();
}
function
flatten
(
nestedObj
,
subsetIdx
)
{
var
flatArr
=
[];
Object
.
keys
(
nestedObj
).
forEach
(
function
(
eType
)
{
Object
.
keys
(
nestedObj
[
eType
]).
forEach
(
function
(
subsetIdx
)
{
for
(
i
=
0
;
i
<
nestedObj
[
eType
][
subsetIdx
].
length
;
i
++
)
{
flatArr
.
push
({
entity
:
nestedObj
[
eType
][
subsetIdx
][
i
].
key
,
nerType
:
eType
,
value
:
nestedObj
[
eType
][
subsetIdx
][
i
].
values
});
}
});
});
return
flatArr
;
}
function
updateEntityType
(
t
)
{
if
(
entityType
!==
t
)
{
entityType
=
t
;
d3
.
select
(
"#data-select"
).
selectAll
(
"button"
).
classed
(
"pure-button-active"
,
false
);
d3
.
select
(
"#"
+
t
+
"Butt"
).
classed
(
"pure-button-active"
,
true
)
visualize
(
t
,
timeScale
);
}
}
function
setTimescaleText
(
t
)
{
e
=
d3
.
select
(
"#timescale-label"
).
node
();
if
(
t
===
"0"
)
e
.
textContent
=
"All time"
;
else
if
(
t
===
"1"
)
e
.
textContent
=
"Years"
;
else
if
(
t
===
"2"
)
e
.
textContent
=
"Months"
;
else
if
(
t
===
"3"
)
e
.
textContent
=
"Days"
;
}
function
updateTimescale
(
t
)
{
timeScale
=
t
;
nestedData
=
nestData
(
allData
,
timeScale
);
visualize
(
entityType
,
t
);
}
window
.
onload
=
init
();
</script>
</body>
</html>
Event Timeline
Log In to Comment