215 lines
6.1 KiB
JavaScript
215 lines
6.1 KiB
JavaScript
//'use strict';
|
|
|
|
//d3 || require('d3');
|
|
//var dagreD3 = require('dagre-d3');
|
|
//var jquery = require('jquery');
|
|
//var $ = jquery;
|
|
|
|
var ParseViewer = function(params) {
|
|
// Container in which the scene template is displayed
|
|
this.selector = params.selector;
|
|
this.container = $(this.selector);
|
|
this.fitToGraph = true;
|
|
this.onClickNodeCallback = params.onClickNodeCallback;
|
|
this.onHoverNodeCallback = params.onHoverNodeCallback;
|
|
this.init();
|
|
return this;
|
|
};
|
|
|
|
ParseViewer.MIN_WIDTH = 100;
|
|
ParseViewer.MIN_HEIGHT = 100;
|
|
|
|
ParseViewer.prototype.constructor = ParseViewer;
|
|
|
|
ParseViewer.prototype.getAutoWidth = function () {
|
|
return Math.max(ParseViewer.MIN_WIDTH, this.container.width());
|
|
};
|
|
|
|
ParseViewer.prototype.getAutoHeight = function () {
|
|
return Math.max(ParseViewer.MIN_HEIGHT, this.container.height() - 20);
|
|
};
|
|
|
|
ParseViewer.prototype.init = function () {
|
|
var canvasWidth = this.getAutoWidth();
|
|
var canvasHeight = this.getAutoHeight();
|
|
this.parseElem = d3.select(this.selector)
|
|
.append('svg')
|
|
.attr({'width': canvasWidth, 'height': canvasHeight})
|
|
.style({'width': canvasWidth, 'height': canvasHeight});
|
|
console.log(this.parseElem);
|
|
this.graph = null;
|
|
this.graphRendered = false;
|
|
|
|
this.controls = $('<div class="text"></div>');
|
|
this.container.append(this.controls);
|
|
};
|
|
|
|
var GraphBuilder = function(roots) {
|
|
// Create the input graph
|
|
this.graph = new dagreD3.graphlib.Graph()
|
|
.setGraph({})
|
|
.setDefaultEdgeLabel(function () {
|
|
return {};
|
|
});
|
|
this.visitIndex = 0;
|
|
//console.log('building graph', roots);
|
|
for (var i = 0; i < roots.length; i++) {
|
|
this.build(roots[i]);
|
|
}
|
|
};
|
|
|
|
GraphBuilder.prototype.build = function(node) {
|
|
console.log(node);
|
|
// Track my visit index
|
|
this.visitIndex++;
|
|
node.visitIndex = this.visitIndex;
|
|
|
|
// Add a node
|
|
var nodeData = node; // TODO: replace with semantic data
|
|
var nodeLabel = node.label;
|
|
var nodeIndex = node.visitIndex;
|
|
var nodeClass = 'parse-RULE';
|
|
|
|
this.graph.setNode(nodeIndex, { label: nodeLabel, class: nodeClass, data: nodeData });
|
|
if (node.parent) {
|
|
this.graph.setEdge(node.parent.visitIndex, nodeIndex, {
|
|
class: 'parse-EDGE'
|
|
});
|
|
}
|
|
|
|
if (node.isTerminal) {
|
|
this.visitIndex++;
|
|
nodeIndex = this.visitIndex;
|
|
nodeLabel = node.text;
|
|
nodeClass = 'parse-TERMINAL';
|
|
|
|
this.graph.setNode(nodeIndex, { label: nodeLabel, class: nodeClass, data: nodeData });
|
|
this.graph.setEdge(node.visitIndex, nodeIndex, {
|
|
class: 'parse-EDGE'
|
|
});
|
|
} else if (node.children) {
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
this.build(node.children[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
ParseViewer.prototype.updateGraphPosition = function (svg, g, minWidth, minHeight) {
|
|
if (this.fitToGraph) {
|
|
minWidth = g.graph().width;
|
|
minHeight = this.getAutoHeight();
|
|
}
|
|
adjustGraphPositioning(svg, g, minWidth, minHeight);
|
|
};
|
|
|
|
function adjustGraphPositioning(svg, g, minWidth, minHeight) {
|
|
// Resize svg
|
|
var newWidth = Math.max(minWidth, g.graph().width);
|
|
var newHeight = Math.max(minHeight, g.graph().height + 40);
|
|
svg.attr({'width': newWidth, 'height': newHeight});
|
|
svg.style({'width': newWidth, 'height': newHeight});
|
|
// Center the graph
|
|
var svgGroup = svg.select('g');
|
|
var xCenterOffset = (svg.attr('width') - g.graph().width) / 2;
|
|
svgGroup.attr('transform', 'translate(' + xCenterOffset + ', 20)');
|
|
svg.attr('height', g.graph().height + 40);
|
|
svg.style('height', g.graph().height + 40);
|
|
}
|
|
|
|
ParseViewer.prototype.renderGraph = function (svg, g, parse) {
|
|
// Create the renderer
|
|
var render = new dagreD3.render();
|
|
// Run the renderer. This is what draws the final graph.
|
|
var svgGroup = svg.select('g');
|
|
render(svgGroup, g);
|
|
|
|
var scope = this;
|
|
var nodes = svgGroup.selectAll('g.node');
|
|
nodes.on('click',
|
|
function (d) {
|
|
var v = d;
|
|
var node = g.node(v);
|
|
if (scope.onClickNodeCallback) {
|
|
scope.onClickNodeCallback(node.data);
|
|
}
|
|
console.log(g.node(v));
|
|
}
|
|
);
|
|
|
|
nodes.on('mouseover',
|
|
function (d) {
|
|
var v = d;
|
|
var node = g.node(v);
|
|
if (scope.onHoverNodeCallback) {
|
|
scope.onHoverNodeCallback(node.data);
|
|
}
|
|
}
|
|
);
|
|
|
|
this.updateGraphPosition(svg, g, svg.attr('width'), svg.attr('height'));
|
|
this.graphRendered = true;
|
|
};
|
|
|
|
ParseViewer.prototype.showParse = function (root) {
|
|
this.showParses([root]);
|
|
};
|
|
|
|
ParseViewer.prototype.showParses = function (roots) {
|
|
// Take parse and create a graph
|
|
var gb = new GraphBuilder(roots);
|
|
var g = gb.graph;
|
|
|
|
g.nodes().forEach(function (v) {
|
|
var node = g.node(v);
|
|
// Round the corners of the nodes
|
|
node.rx = node.ry = 5;
|
|
});
|
|
|
|
var svg = this.parseElem;
|
|
svg.selectAll('*').remove();
|
|
var svgGroup = svg.append('g');
|
|
this.graph = g;
|
|
this.parse = roots;
|
|
if (this.container.is(':visible')) {
|
|
if (roots.length > 0) {
|
|
this.renderGraph(svg, this.graph, this.parse);
|
|
}
|
|
} else {
|
|
this.graphRendered = false;
|
|
}
|
|
};
|
|
|
|
ParseViewer.prototype.showAnnotation = function (annotation) {
|
|
var parses = [];
|
|
for (var i = 0; i < annotation.sentences.length; i++) {
|
|
var s = annotation.sentences[i];
|
|
if (s && s.parseTree) {
|
|
parses.push(s.parseTree);
|
|
}
|
|
}
|
|
this.showParses(parses);
|
|
};
|
|
|
|
ParseViewer.prototype.onResize = function () {
|
|
var canvasWidth = this.getAutoWidth();
|
|
var canvasHeight = this.getAutoHeight();
|
|
var svg = this.parseElem;
|
|
|
|
// Center the graph
|
|
var svgGroup = svg.select('g');
|
|
if (svgGroup && this.graph) {
|
|
if (!this.graphRendered) {
|
|
svg.attr({'width': canvasWidth, 'height': canvasHeight});
|
|
svg.style({'width': canvasWidth, 'height': canvasHeight});
|
|
this.renderGraph(svg, this.graph, this.parse);
|
|
} else {
|
|
this.updateGraphPosition(svg, this.graph, canvasWidth, canvasHeight);
|
|
}
|
|
} else {
|
|
svg.attr({'width': canvasWidth, 'height': canvasHeight});
|
|
svg.style({'width': canvasWidth, 'height': canvasHeight});
|
|
}
|
|
};
|
|
|
|
// Exports
|
|
//module.exports = ParseViewer;
|