Last active
September 26, 2015 16:30
-
-
Save mlent/4a08236e3d07514357c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var parsetree = function(selector, options) { | |
this.el = document.querySelector(selector); | |
this.options = options || {}; | |
if (this.el == null) | |
console.log("Could not find DOM object"); | |
return this; | |
}; | |
// For our purposes, I'll hardcode our data in. | |
parsetree.prototype.init = function() { | |
words = [ | |
{ id: 1, head: 3, relation: "OBJ", value: "ταῦτα" }, | |
{ id: 2, head: 3, relation: "AuxY", value: "γὰρ" }, | |
{ id: 3, head: 0, relation: "PRED", value: "εἶχον", }, | |
{ id: 4, head: 3, relation: "SBJ", value: "Ἀθηναῖοι" }, | |
{ id: 5, head: 1, relation: "ATR", value: "Πελοποννησίων" }, | |
{ id: 6, head: 0, relation: "AuxK", value: "." } | |
]; | |
// We'll convert our flat word object into hierarchical data -- read on to find out how! | |
this.data = this.convertData(words); | |
this.render(); | |
return this; | |
}; | |
parsetree.prototype.convertData = function(words) { | |
// Create a root node | |
var rootNode = { 'id': 0, 'value': 'root', 'pos': 'root' }; | |
words.push(rootNode); | |
var dataMap = words.reduce(function(map, node) { | |
map[node.id] = node; | |
return map; | |
}, {}); | |
var treeData = []; | |
words.forEach(function(node) { | |
var head = dataMap[node.head]; | |
// Then, create the hierarchical data d3 needs | |
if (head) | |
(head.children || (head.children = [])).push(node); | |
else | |
treeData.push(node); | |
}); | |
return treeData; | |
}; | |
parsetree.prototype.render = function () { | |
// To keep multiple instances from stomping on each other's data/d3 references | |
this.tree = d3.layout.tree().nodeSize([100, 50]); | |
// Tell our tree how to decide how to separate the nodes | |
this.tree.separation(function (a, b) { | |
var w1 = (a.value.length > a.relation.length) ? a.value.length : a.relation.length; | |
var w2 = (b.value.length > b.relation.length) ? b.value.length : b.relation.length; | |
var scale = 0.13; | |
return Math.ceil((w1 * scale) + (w2 * scale) / 2); | |
}); | |
// Create our SVG elements | |
// this.svg is our reference to the parent SVG element | |
this.svg = d3.select(this.el).append('svg') | |
.attr('class', 'svg-container') | |
.style('width', 700) | |
.style('overflow', 'auto'); | |
// this.canvas is the group () that the actual tree goes into | |
this.canvas = this.svg.append('g') | |
.attr('class', 'canvas'); | |
// and we nest another one inside to allow zooming and panning | |
this.canvas.append('g') | |
.attr('transform', 'translate(' + (this.options.width || 500) + ', ' + (this.options.marginTop || 10) + ') scale(' + (this.options.initialScale || .8) + ')'); | |
// And at last, we tell the tree to consider our data. | |
this.root = this.data[0]; | |
// this.update is called whenever our data changes | |
this.update(this.root); | |
return this; | |
}; | |
parsetree.prototype.update = function (source) { | |
// This function tells our tree to be oriented vertically instead of horizontally | |
var diagonal = d3.svg.diagonal() | |
.projection(function (d) { | |
return [d.x, d.y]; | |
}); | |
var nodes = this.tree(this.root).reverse(), | |
links = this.tree.links(nodes); | |
nodes.forEach(function (d) { | |
d.y = d.depth * 100; | |
}); | |
var node = this.svg.select('.canvas g') | |
.selectAll('g.node') | |
.data(nodes, function (d, i) { | |
return d.id || (d.id = ++i); | |
}); | |
var nodeEnter = node.enter() | |
.append('g') | |
.attr('class', 'node') | |
.attr('transform', function (d) { | |
return 'translate(' + source.x + ', ' + source.y + ')'; | |
}); | |
nodeEnter.append('circle') | |
.attr('r', 10) | |
.style('stroke', '#000') | |
.style('stroke-width', '3px') | |
.style('fill', '#FFF'); | |
// Our Greek Word | |
nodeEnter.append('text') | |
.attr('y', function (d, i) { | |
return (d.pos == 'root') ? -30 : 15; | |
}) | |
.attr('dy', '14px') | |
.attr('text-anchor', 'middle') | |
.text(function (d) { | |
return d.value; | |
}) | |
.style('fill', function (d, i) { | |
return (d.pos == 'root') ? '#CCC' : '#333'; | |
}) | |
.style('font-family', 'Cambria, Serif') | |
.style('letter-spacing', '2px') | |
.style('font-size', '18px') | |
.style('fill-opacity', 1); | |
// Relation of Node to Parent | |
nodeEnter.append('text') | |
.attr('y', function (d, i) { | |
return (d.pos == 'root') ? 0 : -30; | |
}) | |
.attr('dy', '12px') | |
.attr('text-anchor', 'middle') | |
.attr('class', 'label') | |
.style('font-family', 'sans-serif') | |
.style('font-size', '12px') | |
.style('font-weight', 500) | |
.style('letter-spacing', '1px') | |
.style('fill', '#666') | |
.text(function (d) { | |
return d.relation; | |
}); | |
var nodeUpdate = node.transition() | |
.duration(this.options.duration || 500) | |
.attr('transform', function (d) { | |
return 'translate(' + d.x + ', ' + d.y + ')'; | |
}); | |
var link = this.svg.select('.canvas g') | |
.selectAll('path.link') | |
.data(links, function (d) { | |
return d.target.id; | |
}); | |
link.enter() | |
.insert('path', 'g') | |
.attr('class', 'link') | |
.style('stroke', '#CCC') | |
.style('stroke-width', '2px') | |
.style('fill', 'none') | |
.attr('d', function (d) { | |
var o = { | |
x: source.x, | |
y: source.y | |
}; | |
return diagonal({ | |
source: o, | |
target: o | |
}); | |
}); | |
link.transition() | |
.duration(this.options.duration || 500) | |
.attr('d', diagonal); | |
nodes.forEach(function (d, i) { | |
d.x0 = d.x; | |
d.y0 = d.y; | |
}); | |
}; | |
new parsetree('div[data-toggle="parsetree"]').init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<div data-toggle="parsetree"></div> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment