Chinese dictionaries have organized their thousands of characters with the radical system for the last few hundred years. In this visualization we lay out all 214 standard radicals. Clicking on one will rapidly overlay all the characters with that radical.
This visualization is showing characters from about 20,000 of the most commonly used CJK characters
###The data
The data is powered by the Unicode Unihan database.
It was much easier to work with thanks to the Chinese Character Web API
An excellent example of looking up Chinese characters by their radical: http://hanzi.hemiola.com/
How does typing in Chinese work?
Simplified characters by radical
forked from enjalot's block: 中文: simplified characters
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
</head>
<style>
body {
margin: 0;
position: fixed;
top: 0; left: 0;
width: 960px;
height: 500px;
}
.char {
font-size: 23px;
text-align: center;
position:absolute;
bottom:15px;
right: 220px;
color: white;
}
.progress {
position:absolute;
bottom: 5px;
left: 210px;
height: 5px;
width: 530px;
border: 1px solid gray;
}
.marker {
width: 5px;
height: 5px;
background-color: white;
}
canvas {
width: 100%;
height: 100%;
}
.radical {
font-size: 23px;
margin: 1px;
font-family: "Times";
border-bottom: 1px solid black;
}
.radicals-left {
width: 200px;
height: 100%;
position:absolute;
top:5px; left: 10px;
}
.radicals-left .radical {
float:left;
}
.radicals-right {
width: 200px;
height: 100%;
position:absolute;
top:5px; right: 10px;
}
.radicals-right .radical {
float:right;
}
</style>
<body>
<canvas></canvas>
<div class="char">中</div>
<div class="radicals-left"></div>
<div class="radicals-right"></div>
<div class="progress">
<div class="marker"></div>
</div>
<script>
var bbox = document.body.getBoundingClientRect();
var width = bbox.width;
var height = bbox.height;
var duration = 100;
var bgColor = "#10131d";
var fontSize = height/1.1;
var radicalColors = d3.scale.linear()
.range(["#919191", "#ffffff"])
.interpolate(d3.interpolateRgb)
var canvas = d3.select("canvas").node();
var ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = "lighter";
ctx.font = fontSize/3.3 + "px Times";
ctx.textAlign = "center";
d3.select("body").style("background-color", bgColor);
var char = d3.select(".char")
var marker = d3.select(".marker")
// we want to change these when someone clicks on the radical
var start;
var index;
var radical = "稣";
var data;
var fraction
var characters;
function go() {
ctx.clearRect(0, 0, width, height);
start = Date.now();
index = 0;
var c;
data = [];
for(var i = 0; i < characters.length; i++) {
c = characters[i];
if(c.r === radical) data.push(c);
};
fraction = 1/data.length;
if(fraction < 0.004) fraction = 0.004;
if(fraction > 0.2) fraction = 0.2;
console.log("fraction", fraction)
char.text(radical)
d3.selectAll("div.radical")
.style("border-bottom", "1px solid black")
.filter(function(r) { return r.string === radical })
.style("border-bottom", "1px solid white")
}
var rlookup = {};
d3.json("radicals.json", function(err, radicals) {
console.log("radical", radicals[0]);
radicals.forEach(function(r) {
r.actualCount = 0;
rlookup[r.string] = r;
})
d3.json("traditional.json", function(err, chars){
characters = chars;
console.log("character", chars[0])
var c, r;
var maxCount = 0;
for(var i = 0; i < characters.length; i++) {
c = characters[i];
r = rlookup[c.r]
r.actualCount++;
if(r.actualCount > maxCount) maxCount = r.actualCount;
}
radicalColors.domain([0, maxCount]);
var left = radicals.slice(0, 107)
var right = radicals.slice(107)
d3.select(".radicals-left").selectAll("div.radical")
.data(left)
.enter().append("div").classed("radical", true)
.text(function(d) { return d.string })
.style("color", function(d) { return radicalColors(d.actualCount) })
.filter(function(r) { return r.actualCount })
.style("text-shadow", "0 0 0.2em #b6b9b6")
.style("cursor", "pointer")
.on("click", function(d) {
radical = d.string;
go();
d3.select(this).style("border-bottom", "1px solid white");
})
d3.select(".radicals-right").selectAll("div.radical")
.data(right)
.enter().append("div").classed("radical", true)
.text(function(d) { return d.string })
.style("color", function(d) { return radicalColors(d.actualCount) })
.filter(function(r) { return r.actualCount })
.style("text-shadow", "0 0 0.2em #b6b9b6")
.style("cursor", "pointer")
.on("click", function(d) {
radical = d.string;
go();
})
go();
//timer related
start = Date.now();
index = 0;
d3.timer(function(elapsed) {
var now = Date.now(), duration = now - start;
if (duration >= duration) {
start = now;
if(!data[index]) { return false; }
char.text(data[index].c);
ctx.fillStyle = "rgba(255, 255, 255, " + fraction + ")"
ctx.fillText(data[index].c, 150,115);
}
marker.style("width", 530 * (index+1)/data.length + "px");
if(++index >= data.length) { return false;};
})
})
})
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js