//'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 = $('
'); 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;