1 function getRelativePath( action ) {
2 path_elements = window.location.pathname.split('/');
3 if( path_elements[1].length > 0 ) {
4 return window.location.pathname.split('/')[1] + '/' + action;
10 function svgLoaded() {
11 $('ellipse').attr( {stroke:'black', fill:'#fff'} );
12 ncpath = getRelativePath( 'node_click' );
13 var jqjson = $.getJSON( ncpath, 'node_id=null', function(data) {
14 $.each( data, function(item, node_id_and_state) {
15 if( node_id_and_state[1] == 1 ) {
16 node_ellipse = $('.node').children('title').filter( function(index) {
17 return $(this).text() == node_id_and_state[0];
18 }).siblings('ellipse');
19 node_ellipse.attr( {stroke:'green', fill:'#b3f36d'} );
20 $('#constructedtext').append( node_ellipse.siblings('text').text() + ' ' );
22 if( node_id_and_state[1] == null ) {
23 $('#constructedtext').append( ' … ' );
31 function add_node_objs() {
32 $('ellipse[fill="#fff"]').each( function() {
33 $(this).data( 'node_obj', new node_obj( $(this) ) );
38 function get_node_obj( node_id ) {
39 return $('.node').children('title').filter( function(index) {
40 return $(this).text() == node_id;
41 }).siblings('ellipse').data( 'node_obj' );
44 function get_edge( edge_id ) {
45 return $('.edge').filter( function(index) {
46 return $(this).children( 'title' ).text() == $('<div/>').html(edge_id).text() ;
50 function node_obj(ellipse) {
51 this.ellipse = ellipse;
58 this.node_elements = node_elements_for(self.ellipse);
60 this.super_node = null;
62 this.dblclick_listener = function(evt) {
63 node_id = self.ellipse.siblings('title').text();
64 ncpath = getRelativePath( 'node_click' );
65 var jqjson = $.getJSON( ncpath, 'node_id=' + node_id, function(data) {
66 $('#constructedtext').empty();
67 $.each( data, function(item, node_id_and_state) {
68 node = get_node_obj( node_id_and_state[0] );
69 // 1 -> turn the associated SVG node on, put in the associate word in the text box.
70 // 0 -> turn SVG node off.
71 // null -> turn node off, put in ellipsis in text box at the corresponding place.
72 if( node_id_and_state[1] == 1 ) {
73 //TODO: create test suite en refactor this in to more OO! (node and node_ellipse are 'conflated')
74 node_ellipse = $('.node').children('title').filter( function(index) {
75 return $(this).text() == node_id_and_state[0];
76 }).siblings('ellipse');
77 $('#constructedtext').append( node_ellipse.siblings('text').text() + ' ' );
78 if( node ) { node.set_draggable( false ) }
80 if( node ) { node.set_draggable( true ) };
81 if( node_id_and_state[1] == null ) {
82 $('#constructedtext').append( ' … ' );
89 this.set_draggable = function( draggable ) {
91 self.ellipse.attr( {stroke:'black', fill:'#fff'} );
92 self.ellipse.mousedown( this.mousedown_listener );
93 self.ellipse.hover( this.enter_node, this.leave_node );
95 self.ellipse.unbind('mouseenter').unbind('mouseleave').unbind('mousedown');
96 self.ellipse.attr( {stroke:'green', fill:'#b3f36d'} );
100 this.mousedown_listener = function(evt) {
101 evt.stopPropagation();
102 self.x = evt.clientX;
103 self.y = evt.clientY;
104 $('body').mousemove( self.mousemove_listener );
105 $('body').mouseup( self.mouseup_listener );
106 self.ellipse.unbind('mouseenter').unbind('mouseleave')
107 self.ellipse.attr( 'fill', '#ff66ff' );
110 this.mousemove_listener = function(evt) {
111 self.dx = evt.clientX - self.x;
112 self.dy = evt.clientY - self.y;
113 self.move_elements();
116 this.mouseup_listener = function(evt) {
117 if( $('ellipse[fill="#ffccff"]').size() > 0 ) {
118 $('#source_node_id').val( self.ellipse.siblings('title').text() );
119 $('#target_node_id').val( $('ellipse[fill="#ffccff"]').siblings("title").text() );
120 $( '#dialog-form' ).dialog( 'open' );
122 $('body').unbind('mousemove');
123 $('body').unbind('mouseup');
124 self.ellipse.attr( 'fill', '#fff' );
125 self.ellipse.hover( self.enter_node, self.leave_node );
126 if( self.super_node ) {
129 self.reset_elements();
133 this.cpos = function() {
134 return { x: self.ellipse.attr('cx'), y: self.ellipse.attr('cy') };
137 this.get_g = function() {
138 return self.ellipse.parent('g');
141 this.stack_behind = function( collapse_info ) {
142 self.super_node = get_node_obj( collapse_info.target );
143 self.super_node.sub_nodes.push( self );
145 if( collapse_info.edges ) {
146 $.each( collapse_info.edges, function( source_edge_id, target_info ) {
147 get_edge(source_edge_id).attr( 'display', 'none' );
148 target_edge = get_edge(target_info.target);
149 // Unfortunately, the simple solution doesn't work...
150 // target_edge.children( 'text' ).replaceWith( '<text x="2270" y="-59.400001525878906"><tspan text-anchor="middle">A, B</tspan><tspan fill="red">, C</tspan></text>' );
151 // ..so we take the long and winding road...
152 var svg = $('#svgbasics').children('svg').svg().svg('get');
153 textx = target_edge.children( 'text' )[0].x.baseVal.getItem(0).value
154 texty = target_edge.children( 'text' )[0].y.baseVal.getItem(0).value
155 current_label = target_edge.children( 'text' ).text();
156 target_edge.children( 'text' ).remove();
157 texts = svg.createText();
158 texts.span(current_label, {'text-anchor': 'middle'}).span(target_info.label, {fill: 'red'});
159 svg.text(target_edge, textx, texty, texts);
164 this.eclipse = function() {
165 self.dx = new Number( self.super_node.cpos().x ) - new Number( self.cpos().x ) + ( 10 * (self.super_node.sub_nodes.indexOf(self) + 1) );
166 self.dy = new Number( self.super_node.cpos().y ) - new Number( self.cpos().y ) + ( 5 * (self.super_node.sub_nodes.indexOf(self) + 1) );
167 self.move_elements();
168 eclipse_index = self.super_node.sub_nodes.indexOf(self) - 1;
169 if( eclipse_index > -1 ) {
170 self.get_g().insertBefore( self.super_node.sub_nodes[eclipse_index].get_g() );
172 self.get_g().insertBefore( self.super_node.get_g() );
176 this.enter_node = function(evt) {
177 self.ellipse.attr( 'fill', '#ffccff' );
180 this.leave_node = function(evt) {
181 self.ellipse.attr( 'fill', '#fff' );
184 this.move_elements = function() {
185 $.each( self.node_elements, function(index, value) {
186 value.move(self.dx,self.dy);
190 this.reset_elements = function() {
191 $.each( self.node_elements, function(index, value) {
196 this.ellipse.dblclick( this.dblclick_listener );
197 self.set_draggable( true );
200 function svgshape( shape_element ) {
201 this.shape = shape_element;
202 this.move = function(dx,dy) {
203 this.shape.attr( "transform", "translate(" + dx + " " + dy + ")" );
205 this.reset = function() {
206 this.shape.attr( "transform", "translate( 0, 0 )" );
210 function svgpath( path_element ) {
211 this.path = path_element;
212 this.x = this.path.x;
213 this.y = this.path.y;
214 this.move = function(dx,dy) {
215 this.path.x = this.x + dx;
216 this.path.y = this.y + dy;
218 this.reset = function() {
219 this.path.x = this.x;
220 this.path.y = this.y;
224 function node_elements_for( ellipse ) {
225 node_elements = get_edge_elements_for( ellipse );
226 node_elements.push( new svgshape( ellipse.siblings('text') ) );
227 node_elements.push( new svgshape( ellipse ) );
228 return node_elements;
231 function get_edge_elements_for( ellipse ) {
232 edge_elements = new Array();
233 node_id = ellipse.siblings('title').text();
234 edge_in_pattern = new RegExp( node_id + '$' );
235 edge_out_pattern = new RegExp( '^' + node_id );
236 $.each( $('.edge').children('title'), function(index) {
237 title = $(this).text();
238 if( edge_in_pattern.test(title) ) {
239 edge_elements.push( new svgshape( $(this).siblings('polygon') ) );
240 path_segments = $(this).siblings('path')[0].pathSegList;
241 edge_elements.push( new svgpath( path_segments.getItem(path_segments.numberOfItems - 1) ) );
243 if( edge_out_pattern.test(title) ) {
244 path_segments = $(this).siblings('path')[0].pathSegList;
245 edge_elements.push( new svgpath( path_segments.getItem(0) ) );
248 return edge_elements;
251 $(document).ready(function () {
252 $('#graph').ajaxError(function() {
253 console.log( 'Oops.. something went wrong with trying to save this change. Please try again...' );
255 $('#graph').mousedown(function (event) {
258 .data('x', event.clientX)
259 .data('scrollLeft', this.scrollLeft);
261 }).mouseup(function (event) {
262 $(this).data('down', false);
263 }).mousemove(function (event) {
264 if ($(this).data('down') == true ) {
265 this.scrollLeft = $(this).data('scrollLeft') + $(this).data('x') - event.clientX;
267 }).mousewheel(function (event, delta) {
268 this.scrollLeft -= (delta * 30);
270 'overflow' : 'hidden',
271 'cursor' : '-moz-grab'
273 $( "#dialog-form" ).dialog({
280 form_values = $('#collapse_node_form').serialize()
281 ncpath = getRelativePath( 'node_collapse' );
282 var jqjson = $.getJSON( ncpath, form_values, function(data) {
283 $.each( data, function(item, collapse_info) {
284 get_node_obj( item ).stack_behind( collapse_info );
287 $( this ).dialog( "close" );
290 $( this ).dialog( "close" );
294 $('#reason').val( "" ).removeClass( "ui-state-error" );
300 $(window).mouseout(function (event) {
301 if ($('#graph').data('down')) {
303 if (event.originalTarget.nodeName == 'BODY' || event.originalTarget.nodeName == 'HTML') {
304 $('#graph').data('down', false);