var width = 960,
height = 400,
margin = 20,
pad = margin / 2,
padding = 100,
radius = 6,
yfixed = pad + radius;
// Legend variables
var legend_x = 0,
legend_y = 5,
legend_width = 175,
legend_height = 620,
legend_margin = 20
key_y = 40,
key_x = 16,
mapped_y = legend_y + legend_height - 90;
var color = d3.scale.category20();
// Tooltip
var tooltip = d3.select("body").append("div")
.classed("tooltip", true)
.classed("hidden", true);
var graph = getData();
arcDiagram(graph);
// Main
//-----------------------------------------------------
function arcDiagram(graph) {
var radius = d3.scale.sqrt()
.domain([0, 20])
.range([0, 15]);
var svg = d3.select("#chart").append("svg")
.attr("id", "arc")
.attr("width", width)
.attr("height", height);
// create plot within svg
var plot = svg.append("g")
.attr("id", "plot")
.attr("transform", "translate(" + padding + ", " + padding + ")");
// count the paths
graph.links.forEach(function(d, i) {
var pathCount = 0;
for (var j = 0; j < i; j++) {
var otherPath = graph.links[j];
if (otherPath.source === d.source && otherPath.target === d.target) {
pathCount++;
}
}
// console.log(pathCount)
d.pathCount = pathCount;
});
// fix graph links to map to objects
graph.links.forEach(function(d, i) {
d.source = isNaN(d.source) ? d.source : graph.nodes[d.source];
d.target = isNaN(d.target) ? d.target : graph.nodes[d.target];
});
linearLayout(graph.nodes);
drawLinks(graph.links);
drawNodes(graph.nodes);
}
// layout nodes linearly
function linearLayout(nodes) {
nodes.sort(function(a, b) {
return a.uniq - b.uniq;
});
var xscale = d3.scale.linear()
.domain([0, nodes.length - 1])
.range([radius, width - margin - radius]);
nodes.forEach(function(d, i) {
d.x = xscale(i);
d.y = yfixed;
});
}
function drawNodes(nodes) {
var gnodes = d3.select("#plot").selectAll("g.node")
.data(nodes);
var nodeEnter = gnodes.enter()
.append('g')
.attr("class", "gnode");
nodeEnter.append("circle")
.attr("class", "node")
.attr("id", function(d, i) {
return d.name;
})
.attr("cx", function(d, i) {
return d.x;
})
.attr("cy", function(d, i) {
return d.y;
})
.attr("r", 14)
.style("stroke", function(d, i) {
return color(d.type);
});
// Handling mouseover functions
nodeEnter.selectAll(".node")
.on("mousemove", function(d, i) {
var mouse = d3.mouse(d3.select("body").node());
tooltip
.classed("hidden", false)
.attr("class", "tooltip")
.attr("style", "left:" + (mouse[0] + 20) + "px; top:" + (mouse[1] - 50) + "px")
.html(tooltipText(d));
})
.on("mouseover", nodeOver);
nodeEnter.append("text")
.style("text-anchor", "middle")
.attr("dx", function(d) {
return d.x;
})
.attr("dy", function(d) {
return d.y + 5;
})
.text(function(d) {
return d.token;
});
d3.select("#trial2")
.on("mouseover", trialOver);
}
function drawLinks(links) {
var radians = d3.scale.linear()
.range([Math.PI / 2, 3 * Math.PI / 2]);
var arc = d3.svg.line.radial()
.interpolate("basis")
.tension(0)
.angle(function(d) {
return radians(d);
});
d3.select("#plot").selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.style("stroke-width", function(d) {
return (2 + d.pathCount);
})
.attr("transform", function(d, i) {
var xshift = d.source.x + (d.target.x - d.source.x) / 2;
var yshift = yfixed;
return "translate(" + xshift + ", " + yshift + ")";
})
.attr("d", function(d, i) {
var xdist = Math.abs(d.source.x - d.target.x);
arc.radius(xdist / 2);
var points = d3.range(0, Math.ceil(xdist / 3));
radians.domain([0, points.length - 1]);
return arc(points);
})
.on("mouseover", edgeOver);
}
// Draw legend
//-----------------------------------------------------
function drawLegend(d) {
var legend = svg.append("g")
.attr("class", "legend");
var key = legend.append("g")
// Initial
key.append("circle")
.attr("id", "legend_initial")
.attr("cx", legend_x + key_x)
.attr("cy", legend_y + key_y + 5)
.attr("r", 5)
.style("fill", "blue");
key.append("text")
.attr("class", "legendText")
.attr("id", "legend_initial_label")
.attr("x", legend_x + key_x + 10)
.attr("y", legend_y + 10 + key_y)
.text("Initial");
// Selection
key.append("circle")
.attr("id", "legend_selection")
.attr("cx", function() {
return legend_x + key_x
})
.attr("cy", function() {
return legend_y + legend_margin + key_y + 5
})
.attr("r", 5)
.style("fill", "lightblue");
key.append("text")
.attr("class", "legendText")
.attr("id", "legend_selection_label")
.attr("x", legend_x + key_x + 10)
.attr("y", legend_y + legend_margin + 10 + key_y)
.text("Selection");
// Final
key.append("circle")
.attr("id", "legend_final")
.attr("cx", legend_x + key_x)
.attr("cy", legend_y + 2 * legend_margin + key_y + 5)
.attr("r", 5)
.style("fill", "orange");
key.append("text")
.attr("class", "legendText")
.attr("id", "legend_final_label")
.attr("x", legend_x + key_x + 10)
.attr("y", legend_y + 2 * legend_margin + 10 + key_y)
.text("Final");
// Delete
key.append("circle")
.attr("id", "legend_delete")
.attr("cx", legend_x + key_x)
.attr("cy", legend_y + 3 * legend_margin + key_y + 5)
.attr("r", 5)
.style("fill", "gold");
key.append("text")
.attr("class", "legendText")
.attr("id", "legend_delete_label")
.attr("x", legend_x + key_x + 10)
.attr("y", legend_y + 3 * legend_margin + 10 + key_y)
.text("Delete");
}
function tooltipText(d) {
return "<h5>Information for " + d.token + "</h5>" +
"<table>" +
"<tr>" +
"<td class='field'>Token: </td>" +
"<td>" + d.token + "</td>" +
"</tr>" +
"<tr>" +
"<td class='field'>Dialect: </td>" +
"<td>" + d.dialect + "</td>" +
"</tr>" +
"<tr>" +
"<td class='field'>IME: </td>" +
"<td>" + d.input_method + "</td>" +
"</tr>" +
"<tr>" +
"<td class='field'>Operating System: </td>" +
"<td>" + d.operating_system + "</td>" +
"</tr>" +
"<tr>" +
"<td class='field'>Trial: </td>" +
"<td>" + d.trial + "</td>" +
"</tr>" +
"</table>";
}
function nodeOver(d, i) {
d3.selectAll("path").style("stroke", function(p) {
return p.source == d || p.target == d ? "#17becf" : "#888888"
})
}
function edgeOver(d) {
d3.selectAll("path").style("stroke", function(p) {
return p == d ? "#17becf" : "#888888"
})
}
function trialOver(d) {
var active,
changedOpacity;
d3.select("#arcToken"); // function)
}
function tokenOver(d, i) {
d3.selectAll(this).style("stroke", function(d) {
return p.token == d ? "#17becf" : "#888888"
})
}
function getData() {
return {
"nodes": [{
"token": "x",
"type": "initial",
"uniq": "1",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "ia",
"type": "final",
"uniq": "2",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "1",
"type": "selection",
"uniq": "3",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "m",
"type": "initial",
"uniq": "4",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "a",
"type": "final",
"uniq": "5",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "1",
"type": "selection",
"uniq": "6",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "y",
"type": "initial",
"uniq": "7",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "in",
"type": "final",
"uniq": "8",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "l",
"type": "initial",
"uniq": "9",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "iao",
"type": "final",
"uniq": "10",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "_",
"type": "selection",
"uniq": "11",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "*",
"type": "productive-delete",
"uniq": "12",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "j",
"type": "initial",
"uniq": "13",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "un",
"type": "final",
"uniq": "14",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "z",
"type": "initial",
"uniq": "15",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "1",
"type": "selection",
"uniq": "16",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "*",
"type": "productive-delete",
"uniq": "17",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "j",
"type": "initial",
"uniq": "18",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "iu",
"type": "final",
"uniq": "19",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}, {
"token": "1",
"type": "selection",
"uniq": "20",
"age_group": "18-30",
"dialect": "cantonese",
"gender": "female",
"operating_system": "mac",
"input_method": "apple",
"trial": "2",
"chinese": "",
"english": ""
}],
"links": [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 1
}, {
"source": 0,
"target": 1
}, {
"source": 0,
"target": 1
}, {
"source": 0,
"target": 1
}, {
"source": 0,
"target": 1
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 3
}, {
"source": 1,
"target": 2
}, {
"source": 2,
"target": 3
}, {
"source": 3,
"target": 4
}, {
"source": 3,
"target": 4
}, {
"source": 3,
"target": 4
}, {
"source": 3,
"target": 4
}, {
"source": 3,
"target": 4
}, {
"source": 3,
"target": 4
}, {
"source": 4,
"target": 5
}, {
"source": 4,
"target": 6
}, {
"source": 4,
"target": 6
}, {
"source": 4,
"target": 5
}, {
"source": 4,
"target": 5
}, {
"source": 4,
"target": 5
}, {
"source": 5,
"target": 6
}, {
"source": 5,
"target": 6
}, {
"source": 5,
"target": 6
}, {
"source": 6,
"target": 7
}, {
"source": 6,
"target": 7
}, {
"source": 6,
"target": 7
}, {
"source": 6,
"target": 7
}, {
"source": 6,
"target": 7
}, {
"source": 6,
"target": 7
}, {
"source": 7,
"target": 12
}, {
"source": 7,
"target": 12
}, {
"source": 7,
"target": 12
}, {
"source": 7,
"target": 12
}, {
"source": 7,
"target": 12
}, {
"source": 7,
"target": 8
}, {
"source": 8,
"target": 9
}, {
"source": 9,
"target": 10
}, {
"source": 10,
"target": 11
}, {
"source": 11,
"target": 12
}, {
"source": 12,
"target": 13
}, {
"source": 12,
"target": 13
}, {
"source": 12,
"target": 13
}, {
"source": 12,
"target": 13
}, {
"source": 12,
"target": 13
}, {
"source": 12,
"target": 13
}, {
"source": 13,
"target": 14
}, {
"source": 14,
"target": 15
}, {
"source": 15,
"target": 16
}, {
"source": 16,
"target": 17
}, {
"source": 13,
"target": 17
}, {
"source": 13,
"target": 17
}, {
"source": 13,
"target": 17
}, {
"source": 13,
"target": 17
}, {
"source": 13,
"target": 17
}, {
"source": 17,
"target": 18
}, {
"source": 17,
"target": 18
}, {
"source": 17,
"target": 18
}, {
"source": 17,
"target": 18
}, {
"source": 17,
"target": 18
}, {
"source": 17,
"target": 18
}, {
"source": 18,
"target": 19
}, {
"source": 18,
"target": 19
}, {
"source": 18,
"target": 19
}, {
"source": 18,
"target": 19
}, {
"source": 18,
"target": 19
}]
};
}
@import url(http://fonts.googleapis.com/css?family=Lato:300,400);
body {
font-family: 'Lato', sans-serif;
font-weight: 300;
background: #fff;
}
b {
font-weight: 900;
}
#chart {
position: relative;
}
.outline {
fill: none;
stroke: #888888;
stroke-width: 1px;
}
.hidden {
display: none;
visibility: hidden;
pointer-events: none;
}
.tooltip {
color: #222;
background: #fff;
padding: .5em;
text-shadow: #f5f5f5 0 1px 0;
border-radius: 10px;
border-color: #a6a6a6;
border-width: 1px;
border-style: solid;
box-shadow: 0px 0px 2px 0px #a6a6a6;
opacity: 0.9;
position: absolute;
width: 225px;
display: block;
}
.tooltip h5 {
font-size: 1.05rem;
}
.tooltip p {
font-size: 0.80rem;
}
table {
border: none;
margin: 0;
padding: 0;
border-spacing: 0;
width: 100%;
}
td {
text-align: right;
padding: 2px 0!important;
}
tr {
margin: 0;
background-color: white;
}
.node {
fill: #fff;
stroke: steelblue;
stroke-width: 2.5px;
font: 10px sans-serif;
}
.node text {
color: #333;
}
.link {
fill: none;
stroke: #888888;
stroke-weight: 1px;
stroke-opacity: 0.5;
}
.legend {
font-size: 12px;
}
/*rect {
stroke-width: 2;
}*/
.highlight {
stroke: red;
stroke-weight: 4px;
stroke-opacity: 1.0;
}
.row {
padding-top: 50px;
}
.col-md-3 {
background: rgba(250, 255, 255, 0.5);
border-left: 1px solid #333;
height: 100%;
}
#english {
padding: 1em;
background: rgba(250, 255, 255, 1);
border-bottom: 1px solid #ccc;
}
#chinese {
padding: 1em;
background: rgba(250, 255, 255, 1);
border-bottom: 1px solid #ccc;
}
#source {
color: brown;
}
/* Filters */
#accordion {
position: fixed;
width: 20%;
right: 1;
}
.panel-body {
background: rgba(250, 255, 255, 0.5);
}
.panel-default > .panel-heading {
/*background: #fff;*/
}
.panel-heading {
padding: 0;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
}
.panel-group .panel {
border-radius: 0;
}
.panel-group {
margin-bottom: 0;
}
.panel-title a {
color: #333;
text-align: left;
width: 100%;
display: block;
padding: 10px 15px;
font-size: 14px;
outline: none;
}
.panel-title a:hover,
.panel-title a:focus,
.panel-title a:active {
text-decoration: none;
outline: none;
}
.panel-options {
padding: 5px;
}
.legend circle {
fill: none;
stroke: #ccc;
}
.legend text {
fill: #777;
font: 10px sans-serif;
text-anchor: middle;
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Chinese Input</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="visualization.js"></script>
</head>
<body>
<div id="chart"></div>
</body>
</html>