jbjares2

Untitled

Jul 29th, 2015
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. =====================================================================
  2. index.html
  3. =====================================================================
  4. PS.: Nothing important on index.html, to be attached.
  5.  
  6. =====================================================================
  7. Java/Servlet
  8. =====================================================================
  9. PS.: Nothing important on Java/Servlet, to be attached.
  10.  
  11. =====================================================================
  12. linkeditgraph.js (main .js - all the magic happens here)
  13. =====================================================================
  14.  
  15. var drag_line = null;
  16. var force = null;
  17. // handles to link and node element groups
  18. var path = null,
  19.     circle = null;
  20. var loaded = false;
  21. //var lastNodeId = 4;
  22. var lastNodeId = null;
  23. // set up SVG for D3
  24. var width  = 2100,
  25.     height = 950,
  26.     colors = d3.scale.category10();
  27.  
  28. var svg = d3.select('body')
  29.   .append('svg')
  30.   .attr('width', width)
  31.   .attr('height', height);
  32.  
  33. // set up initial nodes and links
  34. //  - nodes are known by 'id', not by index in array.
  35. //  - reflexive edges are indicated on the node (as a bold black circle).
  36. //  - links are always source < target; edge directions are set by 'left' and 'right'.
  37. //nodes and links are coming from Servlet as json, the definition below is deprecated or used if servlet is out.
  38. var nodes = [
  39.     {id: 0, reflexive: false},
  40.     {id: 1, reflexive: true },
  41.     {id: 2, reflexive: false}
  42.   ],
  43.  
  44.   links = [
  45.     {source: nodes[0], target: nodes[1], left: false, right: true },
  46.     {source: nodes[1], target: nodes[2], left: false, right: true }
  47.   ];
  48. //nodes and links are coming from Servlet as json, the definition above is deprecated or used if servlet is out.
  49.  
  50.  
  51.  
  52. //LOOK: initD3ForceLayout function runs once, when the application loads on his first time, in the same fashion of load function.
  53. // init D3 force layout
  54. function initD3ForceLayout(nodes,links){
  55.         force = d3.layout.force()
  56.         .nodes(nodes)
  57.         .links(links)
  58.         .size([width, height])
  59.         .linkDistance(150)
  60.         .charge(-500)
  61.         .on('tick', tick)
  62.            
  63.  
  64.     // define arrow markers for graph links
  65.     svg.append('svg:defs').append('svg:marker')
  66.         .attr('id', 'end-arrow')
  67.         .attr('viewBox', '0 -5 10 10')
  68.         .attr('refX', 6)
  69.         .attr('markerWidth', 3)
  70.         .attr('markerHeight', 3)
  71.         .attr('orient', 'auto')
  72.       .append('svg:path')
  73.         .attr('d', 'M0,-5L10,0L0,5')
  74.         .attr('fill', '#000');
  75.  
  76.     svg.append('svg:defs').append('svg:marker')
  77.         .attr('id', 'start-arrow')
  78.         .attr('viewBox', '0 -5 10 10')
  79.         .attr('refX', 4)
  80.         .attr('markerWidth', 3)
  81.         .attr('markerHeight', 3)
  82.         .attr('orient', 'auto')
  83.       .append('svg:path')
  84.         .attr('d', 'M10,-5L0,0L10,5')
  85.         .attr('fill', '#000');
  86.  
  87.     // line displayed when dragging new nodes
  88.      drag_line = svg.append('svg:path')
  89.       .attr('class', 'link dragline hidden')
  90.       .attr('d', 'M0,0L0,0');
  91.  
  92.     // handles to link and node element groups
  93.      path = svg.append('svg:g').selectAll('path'),
  94.         circle = svg.append('svg:g').selectAll('g');
  95.        
  96. }
  97.  
  98. // mouse event vars
  99. var selected_node = null,
  100.     selected_link = null,
  101.     mousedown_link = null,
  102.     mousedown_node = null,
  103.     mouseup_node = null;
  104.  
  105. function resetMouseVars() {
  106.   mousedown_node = null;
  107.   mouseup_node = null;
  108.   mousedown_link = null;
  109.  
  110. }
  111.  
  112. // update force layout (called automatically each iteration)
  113. function tick() {
  114.   // draw directed edges with proper padding from node centers
  115.   path.attr('d', function(d) {
  116.     var deltaX = d.target.x - d.source.x,
  117.         deltaY = d.target.y - d.source.y,
  118.         dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
  119.         normX = deltaX / dist,
  120.         normY = deltaY / dist,
  121.         sourcePadding = d.left ? 17 : 12,
  122.         targetPadding = d.right ? 17 : 12,
  123.         sourceX = d.source.x + (sourcePadding * normX),
  124.         sourceY = d.source.y + (sourcePadding * normY),
  125.         targetX = d.target.x - (targetPadding * normX),
  126.         targetY = d.target.y - (targetPadding * normY);
  127.    
  128.    
  129.  
  130.     return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
  131.   });
  132.  
  133.   circle.attr('transform', function(d) {
  134.       for(var key in d) {
  135.             var value = d[key];
  136.         }
  137.     return 'translate(' + d.x + ',' + d.y + ')';
  138.   });
  139. }
  140.  
  141. //function createPredicateFilters(up){
  142. //  updateFilters();
  143. //}
  144. // update graph (called when needed)
  145. //=====================================================================================================================
  146. //LOOK: Load function runs once, on application loads on his first time.
  147. function load() {
  148.  
  149. //LOOK: The if below protects this function to run again, after application load.
  150.     if(loaded){
  151.         return;
  152.     }
  153.    
  154. //  literals = json.literals;
  155. //  for(i in json.links){
  156. //      uniquePredicates[json.links[i].name] = 1;
  157. //  }
  158. //  createPredicateFilters(uniquePredicates);
  159.    
  160.     console.log("===> restart");
  161.     //d3.json('http://localhost:8080/JVisualRDFApp/RdfToJsonServlet?url='+encodeURIComponent(myUrl), function(json){
  162.     d3.json('http://localhost:8080/JVisualRDFApp/RdfToJsonServlet?url=<abc>', function(json){
  163.  
  164.             d3.select("#waiting").style("display", "none");
  165.             console.log("===> restart: json content "+json);
  166.             // path (link) group
  167.             console.log("===> init: json.links content "+json.links);
  168.             if(json.links!=null){
  169.                 links = json.links;
  170.             }else{
  171.                 console.log("===> error: json.links is null");
  172.             }
  173.            
  174.             if(json.nodes!=null){
  175.                 nodes = json.nodes;
  176.             }else{
  177.                 console.log("===> error: json.nodes  is null");
  178.             }
  179.             if(json.nodes!=null){
  180.                 console.log(json.nodes.length);
  181.                 lastNodeId = json.nodes.length-1;
  182.             }else{
  183.                 console.log("===> error: json.nodes  is null");
  184.             }
  185.            
  186. //LOOK: initD3ForceLayout function runs once, on application loads on his first time, in the same fashion of load function.
  187.             initD3ForceLayout(nodes,links);
  188.             restart();
  189.             loaded = true;
  190.  
  191.     });
  192.    
  193. }
  194. //=====================================================================================================================
  195.  
  196. function restart(){
  197.     path = path.data(links);
  198.     console.log("===> init: links content "+links);
  199.    
  200.       // update existing links
  201.       path.classed('selected', function(d) { return d === selected_link; })
  202.         .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; })
  203.         .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; });
  204.  
  205.  
  206.       // add new links
  207.       path.enter().append('svg:path')
  208.         .attr('class', 'link')
  209.         .classed('selected', function(d) { return d === selected_link; })
  210.         .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; })
  211.         .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; })
  212.         .style('label', function(d) { return d.right ? 'url(#end-arrow)' : ''; })
  213.         .on('mousedown', function(d) {
  214.           if(d3.event.ctrlKey) return;
  215.  
  216.           // select link
  217.           mousedown_link = d;
  218.           if(mousedown_link === selected_link) selected_link = null;
  219.           else selected_link = mousedown_link;
  220.           selected_node = null;
  221.           restart();
  222.         });
  223.      
  224.      
  225.  
  226.       // remove old links
  227.       path.exit().remove();
  228.  
  229.  
  230.       // circle (node) group
  231.       // NB: the function arg is crucial here! nodes are known by id, not by index!
  232.       circle = circle.data(nodes, function(d) { return d.id; });
  233.  
  234.       // update existing nodes (reflexive & selected visual states)
  235.       circle.selectAll('circle')
  236.         .style('fill', function(d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
  237.         .classed('reflexive', function(d) { return d.reflexive; });
  238.  
  239.       // add new nodes
  240.       var g = circle.enter().append('svg:g');
  241.  
  242.       g.append('svg:circle')
  243.         .attr('class', 'node')
  244.         .attr('r', 12)
  245.         .style('fill', function(d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
  246.         .style('stroke', function(d) { return d3.rgb(colors(d.id)).darker().toString(); })
  247.         .classed('reflexive', function(d) { return d.reflexive; })
  248.         .on('mouseover', function(d) {
  249.           if(!mousedown_node || d === mousedown_node) return;
  250.           // enlarge target node
  251.           d3.select(this).attr('transform', 'scale(1.1)');
  252.         })
  253. //=====================================================================================================================
  254. //LOOK: The code below is not complete, once I can't see the new edited node's name. Here's where I need help :)
  255. //Please, see the video, if necessary, to understand the problem better. (Video: https://www.youtube.com/watch?v=T1eguX14icY&feature=youtu.be)
  256. //=====================================================================================================================
  257.         .on('dblclick', function(d){
  258.                 var nodeName = prompt("Define a name, for this node.");
  259.                 if (nodeName != null) {
  260.                     node.name = nodeName;
  261.                       circle.selectAll('circle')
  262.                         .style('fill', function(d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
  263.                         .classed('reflexive', function(d) { return d.reflexive; })
  264.                         .classed('name', function(d) { return d.name; });
  265.                     nodes.push(node);
  266.                       // remove old nodes
  267.                       circle.exit().remove();
  268.  
  269.                       // set the graph in motion
  270.                       force.start();
  271.                 }
  272.             })
  273. //=====================================================================================================================
  274.         .on('mouseout', function(d) {
  275.           if(!mousedown_node || d === mousedown_node) return;
  276.           // unenlarge target node
  277.           d3.select(this).attr('transform', '');
  278.         })
  279.         .on('mousedown', function(d) {
  280.           if(d3.event.ctrlKey) return;
  281.  
  282.           // select node
  283.           mousedown_node = d;
  284.           if(mousedown_node === selected_node) selected_node = null;
  285.           else selected_node = mousedown_node;
  286.           selected_link = null;
  287.  
  288.           // reposition drag line
  289.           drag_line
  290.             .style('marker-end', 'url(#end-arrow)')
  291.             .classed('hidden', false)
  292.             .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + mousedown_node.x + ',' + mousedown_node.y);
  293.  
  294.           restart();
  295.         })
  296.         .on('mouseup', function(d) {
  297.           if(!mousedown_node) return;
  298.  
  299.           // needed by FF
  300.           drag_line
  301.             .classed('hidden', true)
  302.             .style('marker-end', '');
  303.  
  304.           // check for drag-to-self
  305.           mouseup_node = d;
  306.           if(mouseup_node === mousedown_node) { resetMouseVars(); return; }
  307.  
  308.           // unenlarge target node
  309.           d3.select(this).attr('transform', '');
  310.  
  311.           // add link to graph (update if exists)
  312.           // NB: links are strictly source < target; arrows separately specified by booleans
  313.           var source, target, direction;
  314.           if(mousedown_node.id < mouseup_node.id) {
  315.             source = mousedown_node;
  316.             target = mouseup_node;
  317.             direction = 'right';
  318.           } else {
  319.             source = mouseup_node;
  320.             target = mousedown_node;
  321.             direction = 'left';
  322.           }
  323.  
  324.           var link;
  325.           link = links.filter(function(l) {
  326.             return (l.source === source && l.target === target);
  327.           })[0];
  328.  
  329.           if(link) {
  330.             link[direction] = true;
  331.           } else {
  332.             link = {source: source, target: target, left: false, right: false};
  333.             link[direction] = true;
  334.             links.push(link);
  335.           }
  336.  
  337.           // select new link
  338.           selected_link = link;
  339.           selected_node = null;
  340.           restart();
  341.         });
  342.  
  343.       // show node names
  344.       g.append('svg:text')
  345.           .attr('x', 0)
  346.           .attr('y', 4)
  347.           .attr('class', 'name')
  348.           .text(function(d) { return d.name; });
  349. //        .attr('class', 'id')
  350. //        .text(function(d) { return d.id; });
  351.      
  352.       // remove old nodes
  353.       circle.exit().remove();
  354.  
  355.       // set the graph in motion
  356.       force.start();
  357. }
  358.  
  359. //=====================================================================================================================
  360. //LOOK: This function is responsible for the new node creation on mousedown event. So,
  361. //I added a javascript prompt to ask the node name, before the node creation, as could be seen at commeNt name "CUSTOM"
  362. function mousedown() {
  363.   // prevent I-bar on drag
  364.   //d3.event.preventDefault();
  365.  
  366.   // because :active only works in WebKit?
  367.   svg.classed('active', true);
  368.  
  369.   if(d3.event.ctrlKey || mousedown_node || mousedown_link) return;
  370.  
  371.   // insert new node at point
  372.   var point = d3.mouse(this),
  373.       node = {id: ++lastNodeId, reflexive: false};
  374.   node.x = point[0];
  375.   node.y = point[1];
  376.  
  377. //LOOK: CUSTOM - START
  378.     var nodeName = prompt("Define a name, for this node.");
  379.     console.log("prompt");
  380.     if (nodeName == null) {
  381.         console.log("nodeName == null");
  382.         return;
  383.     }else{
  384.         node.name = nodeName;
  385.     }
  386. //LOOK: CUSTOM - END
  387.  
  388.   nodes.push(node);
  389.  
  390.   restart();
  391. }
  392. //=====================================================================================================================
  393. function mousemove() {
  394.   if(!mousedown_node) return;
  395.  
  396.   // update drag line
  397.   drag_line.attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + d3.mouse(this)[0] + ',' + d3.mouse(this)[1]);
  398.  
  399.   restart();
  400. }
  401.  
  402. function mouseup() {
  403.   if(mousedown_node) {
  404.     // hide drag line
  405.     drag_line
  406.       .classed('hidden', true)
  407.       .style('marker-end', '');
  408.   }
  409.  
  410.   // because :active only works in WebKit?
  411.   svg.classed('active', false);
  412.  
  413.   // clear mouse event vars
  414.   resetMouseVars();
  415. }
  416.  
  417. function spliceLinksForNode(node) {
  418.   var toSplice = links.filter(function(l) {
  419.     return (l.source === node || l.target === node);
  420.   });
  421.   toSplice.map(function(l) {
  422.     links.splice(links.indexOf(l), 1);
  423.   });
  424. }
  425.  
  426. // only respond once per keydown
  427. var lastKeyDown = -1;
  428.  
  429. function keydown() {
  430.   d3.event.preventDefault();
  431.  
  432.   if(lastKeyDown !== -1) return;
  433.   lastKeyDown = d3.event.keyCode;
  434.  
  435.   // ctrl
  436.   if(d3.event.keyCode === 17) {
  437.     circle.call(force.drag);
  438.     svg.classed('ctrl', true);
  439.   }
  440.  
  441.   if(!selected_node && !selected_link) return;
  442.   switch(d3.event.keyCode) {
  443.     case 8: // backspace
  444.     case 46: // delete
  445.       if(selected_node) {
  446.         nodes.splice(nodes.indexOf(selected_node), 1);
  447.         spliceLinksForNode(selected_node);
  448.       } else if(selected_link) {
  449.         links.splice(links.indexOf(selected_link), 1);
  450.       }
  451.       selected_link = null;
  452.       selected_node = null;
  453.       restart();
  454.       break;
  455.     case 66: // B
  456.       if(selected_link) {
  457.         // set link direction to both left and right
  458.         selected_link.left = true;
  459.         selected_link.right = true;
  460.       }
  461.       restart();
  462.       break;
  463.     case 76: // L
  464.       if(selected_link) {
  465.         // set link direction to left only
  466.         selected_link.left = true;
  467.         selected_link.right = false;
  468.       }
  469.       restart();
  470.       break;
  471.     case 82: // R
  472.       if(selected_node) {
  473.         // toggle node reflexivity
  474.         selected_node.reflexive = !selected_node.reflexive;
  475.       } else if(selected_link) {
  476.         // set link direction to right only
  477.         selected_link.left = false;
  478.         selected_link.right = true;
  479.       }
  480.       restart();
  481.       break;
  482.   }
  483. }
  484.  
  485.  
  486.  
  487. function keyup() {
  488.   lastKeyDown = -1;
  489.  
  490.   // ctrl
  491.   if(d3.event.keyCode === 17) {
  492.     circle
  493.       .on('mousedown.drag', null)
  494.       .on('touchstart.drag', null);
  495.     svg.classed('ctrl', false);
  496.   }
  497. }
  498.  
  499. // app starts here
  500. svg.on('mousedown', mousedown)
  501.   .on('mousemove', mousemove)
  502.   .on('mouseup', mouseup);
  503.  
  504. d3.select(window)
  505.   .on('keydown', keydown)
  506.   .on('keyup', keyup);
  507.  
  508. load();
  509. restart();
Advertisement
Add Comment
Please, Sign In to add comment