From 13323b04f22058c499559fdb1a4d1d2c3fe16fc9 Mon Sep 17 00:00:00 2001 From: Rajkumar Sriramulu Date: Mon, 27 Feb 2017 06:40:06 +0530 Subject: [PATCH] added trace to construct elements still work pending in construct and tree code --- js/module/tracer/directed_graph_construct.js | 448 +++++++++++++++++++ js/module/tracer/index.js | 2 + 2 files changed, 450 insertions(+) create mode 100644 js/module/tracer/directed_graph_construct.js diff --git a/js/module/tracer/directed_graph_construct.js b/js/module/tracer/directed_graph_construct.js new file mode 100644 index 0000000..962d0e1 --- /dev/null +++ b/js/module/tracer/directed_graph_construct.js @@ -0,0 +1,448 @@ +'use strict'; + +const Tracer = require('./tracer'); + +const { + refineByType +} = require('../../tracer_manager/util/index'); + +class DirectedGraphConstructTracer extends Tracer { + static getClassName() { + return 'DirectedGraphConstructTracer'; + } + + constructor(name, nodePlacement = null) { + super(name); + this.nodePlacement = nodePlacement; + if (this.isNew) initView(this); + } + + _addNode(G, root, element, parentElement = null) { + this.manager.pushStep(this.capsule, { + type: 'addNode', + arguments: arguments + }); + return this; + } + + _findNode(G, val) { + var idToFind = this.n(val); + var result = null; + for (let i = 0; i < G.length; i++) { + if(G[i].id === idToFind) { + result = G[i]; + break; + } + } + return result; + } + + _visit(G, target, source) { + this.manager.pushStep(this.capsule, { + type: 'visit', + G: G, + target: target, + source: source + }); + return this; + } + + _leave(target, source) { + this.manager.pushStep(this.capsule, { + type: 'leave', + target: target, + source: source + }); + return this; + } + + _setNodePositions(positions) { + this.manager.pushStep(this.capsule, { + type: 'setNodePositions', + positions: positions + }); + return this; + } + + processStep(step, options) { + switch (step.type) { + case 'setTreeData': + this.setTreeData.apply(this, step.arguments); + break; + case 'setNodePositions': + $.each(this.graph.nodes(), (i, node) => { + if (i >= step.positions.length) return false; + const position = step.positions[i]; + node.x = position.x; + node.y = position.y; + }); + break; + case 'addNode': + this.addNode.apply(this, step.arguments); + break; + case 'visit': + case 'leave': + var visit = step.type == 'visit'; + var nodeObject = this._findNode(step.G, step.target); + nodeObject.visited = visit; + nodeObject.isNew = false; + var targetNode = this.graph.nodes(this.n(step.target)); + var color = visit ? this.color.visited : this.color.left; + if(targetNode) { + targetNode.color = color; + if (step.source !== undefined) { + var edgeId = this.e(step.source, step.target); + var edge = this.graph.edges(edgeId); + edge.color = color; + this.graph.dropEdge(edgeId).addEdge(edge); + } + } + if (this.logTracer) { + var source = step.source; + if (source === undefined) source = ''; + this.logTracer.print(visit ? source + ' -> ' + step.target : source + ' <- ' + step.target); + } + break; + default: + super.processStep(step, options); + } + } + + addNode(G, root, node, parent) { + var nodeObject = this.nodeConstruct(node); + var parentObject = this._findNode(G, parent); + if (parentObject) { + nodeObject.parent = parentObject; + nodeObject.level = parentObject.level + 1; + if (this.nodePlacement === null) { + parentObject.children.push(nodeObject); + } else if (this.nodePlacement === 0) { + var isSpliced = false; + var insertIndex = 0; + if (parentObject.children.length > 0) { + for(let i = 0; i < parentObject.children.length; i++) { + var child = parentObject.children[i]; + if(child.originalVal > node) { + isSpliced = true; + break; + } + insertIndex++; + } + } + if(isSpliced) { + parentObject.children.splice(insertIndex, 0, nodeObject); + console.log('exchange Happened'); + } else { + parentObject.children.push(nodeObject); + } + } + } + nodeObject.updateBreadth(); + G.push(nodeObject); + this.drawGraph(G, root, nodeObject.level); + if(node === 4) { + console.log(this.graph.nodes); + } + } + + nodeConstruct(val) { + var nodeObject = { + id: this.n(val), + originalVal: val, + isNew: true, + children: [], + breadth: 0, + level: 1, + parent: null, + visited: false, + updateBreadth: function() { + var oldBreadth = nodeObject.breadth; + if ( nodeObject.children.length > 0 ) { + nodeObject.breadth = nodeObject.children.length % 2 ? 0 : 1; + for (let j = 0; j < nodeObject.children.length; j++) { + nodeObject.breadth += nodeObject.children[j].breadth; + } + } else { nodeObject.breadth = 1; } + if ( oldBreadth !== nodeObject.breadth && nodeObject.parent ) { + nodeObject.parent.updateBreadth(); + } + } + } + return nodeObject; + } + + drawGraph(G, root, nodeLevel) { + const nodes = []; + const edges = []; + var tracer = this; + var drawNode = function (node, parentNode, occupiedBreadth) { + var calculatedX = node.breadth; + if (parentNode) { + calculatedX = parentNode.breadth + occupiedBreadth - node.breadth; + } else if (node.children.length > 0) { + calculatedX = Math.ceil(calculatedX/node.children.length); + } + + nodes.push({ + id: node.id, + label: '' + node.originalVal, + x: calculatedX, + y: node.level - 1, + size: 1, + color: node.isNew ? tracer.color.selected : (node.visited ? tracer.color.visited : tracer.color.default), + weight: 0 + }); + + if ( node.children.length > 0 ) { + var midPoint = node.children.length / 2; + var occupiedBreadth = 0; + for (let j = 0; j < node.children.length; j++) { + var childNode = node.children[j]; + edges.push({ + id: tracer.e(node.originalVal, childNode.originalVal), + source: node.id, + target: childNode.id, + color: node.visited && childNode.visited ? tracer.color.visited : tracer.color.default, + size: 1, + weight: refineByType(childNode.originalVal) + }); + drawNode(childNode, node, occupiedBreadth); + occupiedBreadth += node.breadth; + } + } + } + var rootObject = this._findNode(G, root); + drawNode(rootObject); + + this.graph.clear(); + this.graph.read({ + nodes: nodes, + edges: edges + }); + this.s.camera.goTo({ + x: 0, + y: nodeLevel, + angle: 0, + ratio: 1 + }); + this.refresh(); + + return false; + } + + resize() { + super.resize(); + + this.s.renderers[0].resize(); + this.refresh(); + } + + refresh() { + super.refresh(); + + this.s.refresh(); + } + + clear() { + super.clear(); + + this.clearGraphColor(); + this.refresh(); + } + + clearGraphColor() { + var tracer = this; + + this.graph.nodes().forEach(function (node) { + node.color = tracer.color.default; + }); + this.graph.edges().forEach(function (edge) { + edge.color = tracer.color.default; + }); + } + + n(v) { + return 'n' + v; + } + + e(v1, v2) { + return 'e' + v1 + '_' + v2; + } + + getColor(edge, source, target, settings) { + var color = edge.color, + edgeColor = settings('edgeColor'), + defaultNodeColor = settings('defaultNodeColor'), + defaultEdgeColor = settings('defaultEdgeColor'); + if (!color) + switch (edgeColor) { + case 'source': + color = source.color || defaultNodeColor; + break; + case 'target': + color = target.color || defaultNodeColor; + break; + default: + color = defaultEdgeColor; + break; + } + + return color; + } + + drawLabel(node, context, settings) { + var fontSize, + prefix = settings('prefix') || '', + size = node[prefix + 'size']; + + if (size < settings('labelThreshold')) + return; + + if (!node.label || typeof node.label !== 'string') + return; + + fontSize = (settings('labelSize') === 'fixed') ? + settings('defaultLabelSize') : + settings('labelSizeRatio') * size; + + context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') + + fontSize + 'px ' + settings('font'); + context.fillStyle = (settings('labelColor') === 'node') ? + (node.color || settings('defaultNodeColor')) : + settings('defaultLabelColor'); + + context.textAlign = 'center'; + context.fillText( + node.label, + Math.round(node[prefix + 'x']), + Math.round(node[prefix + 'y'] + fontSize / 3) + ); + } + + drawArrow(edge, source, target, color, context, settings) { + var prefix = settings('prefix') || '', + size = edge[prefix + 'size'] || 1, + tSize = target[prefix + 'size'], + sX = source[prefix + 'x'], + sY = source[prefix + 'y'], + tX = target[prefix + 'x'], + tY = target[prefix + 'y'], + angle = Math.atan2(tY - sY, tX - sX), + dist = 3; + sX += Math.sin(angle) * dist; + tX += Math.sin(angle) * dist; + sY += -Math.cos(angle) * dist; + tY += -Math.cos(angle) * dist; + var aSize = Math.max(size * 2.5, settings('minArrowSize')), + d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)), + aX = sX + (tX - sX) * (d - aSize - tSize) / d, + aY = sY + (tY - sY) * (d - aSize - tSize) / d, + vX = (tX - sX) * aSize / d, + vY = (tY - sY) * aSize / d; + + context.strokeStyle = color; + context.lineWidth = size; + context.beginPath(); + context.moveTo(sX, sY); + context.lineTo( + aX, + aY + ); + context.stroke(); + + context.fillStyle = color; + context.beginPath(); + context.moveTo(aX + vX, aY + vY); + context.lineTo(aX + vY * 0.6, aY - vX * 0.6); + context.lineTo(aX - vY * 0.6, aY + vX * 0.6); + context.lineTo(aX + vX, aY + vY); + context.closePath(); + context.fill(); + } + + drawOnHover(node, context, settings, next) { + var tracer = this; + + context.setLineDash([5, 5]); + var nodeIdx = node.id.substring(1); + this.graph.edges().forEach(function (edge) { + var ends = edge.id.substring(1).split("_"); + if (ends[0] == nodeIdx) { + var color = '#0ff'; + var source = node; + var target = tracer.graph.nodes('n' + ends[1]); + tracer.drawArrow(edge, source, target, color, context, settings); + if (next) next(edge, source, target, color, context, settings); + } else if (ends[1] == nodeIdx) { + var color = '#ff0'; + var source = tracer.graph.nodes('n' + ends[0]); + var target = node; + tracer.drawArrow(edge, source, target, color, context, settings); + if (next) next(edge, source, target, color, context, settings); + } + }); + } +} + +const initView = (tracer) => { + tracer.s = tracer.capsule.s = new sigma({ + renderer: { + container: tracer.$container[0], + type: 'canvas' + }, + settings: { + minArrowSize: 8, + defaultEdgeType: 'arrow', + maxEdgeSize: 2.5, + labelThreshold: 4, + font: 'Roboto', + defaultLabelColor: '#fff', + zoomMin: 0.6, + zoomMax: 1.2, + skipErrors: true, + minNodeSize: .5, + maxNodeSize: 12, + labelSize: 'proportional', + labelSizeRatio: 1.3, + funcLabelsDef(node, context, settings) { + tracer.drawLabel(node, context, settings); + }, + funcHoversDef(node, context, settings, next) { + tracer.drawOnHover(node, context, settings, next); + }, + funcEdgesArrow(edge, source, target, context, settings) { + var color = tracer.getColor(edge, source, target, settings); + tracer.drawArrow(edge, source, target, color, context, settings); + } + } + }); + sigma.plugins.dragNodes(tracer.s, tracer.s.renderers[0]); + tracer.graph = tracer.capsule.graph = tracer.s.graph; +}; + +sigma.canvas.labels.def = function (node, context, settings) { + var func = settings('funcLabelsDef'); + if (func) { + func(node, context, settings); + } +}; +sigma.canvas.hovers.def = function (node, context, settings) { + var func = settings('funcHoversDef'); + if (func) { + func(node, context, settings); + } +}; +sigma.canvas.edges.def = function (edge, source, target, context, settings) { + var func = settings('funcEdgesDef'); + if (func) { + func(edge, source, target, context, settings); + } +}; +sigma.canvas.edges.arrow = function (edge, source, target, context, settings) { + var func = settings('funcEdgesArrow'); + if (func) { + func(edge, source, target, context, settings); + } +}; + +module.exports = DirectedGraphConstructTracer; diff --git a/js/module/tracer/index.js b/js/module/tracer/index.js index 45f8275..d360520 100644 --- a/js/module/tracer/index.js +++ b/js/module/tracer/index.js @@ -7,6 +7,7 @@ const Array2DTracer = require('./array2d'); const ChartTracer = require('./chart'); const CoordinateSystemTracer = require('./coordinate_system'); const DirectedGraphTracer = require('./directed_graph'); +const DirectedGraphConstructTracer = require('./directed_graph_construct'); const UndirectedGraphTracer = require('./undirected_graph'); const WeightedDirectedGraphTracer = require('./weighted_directed_graph'); const WeightedUndirectedGraphTracer = require('./weighted_undirected_graph'); @@ -19,6 +20,7 @@ module.exports = { ChartTracer, CoordinateSystemTracer, DirectedGraphTracer, + DirectedGraphConstructTracer, UndirectedGraphTracer, WeightedDirectedGraphTracer, WeightedUndirectedGraphTracer -- GitLab