annotate toolboxes/graph_visualisation/graphViz4Matlab/util/graphViz4MatlabNode.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 classdef graphViz4MatlabNode < dynamicprops & hgsetget
wolffd@0 2 % This class represents a drawable node in an arbitrary graph.
wolffd@0 3 %
wolffd@0 4 % Public properties can be set using the standard Matlab set method as in
wolffd@0 5 % set(node,'curvature',[0,0],'linesytle','--','linecolor','g'). Call
wolffd@0 6 % node.redraw to redraw it after changing properties.
wolffd@0 7 %
wolffd@0 8 % Nodes are not really designed to live on their own, they should be
wolffd@0 9 % aggregated into a graph object responsible for layout.
wolffd@0 10 %
wolffd@0 11 % Matthew Dunham
wolffd@0 12 % University of British Columbia
wolffd@0 13 % http://www.cs.ubc.ca/~mdunham/
wolffd@0 14
wolffd@0 15 properties
wolffd@0 16 label; % displayed name for the node
wolffd@0 17 splitLabel; % label split in the middle
wolffd@0 18 useFullLabel = false; % if true, the full non-split label is used regardles of how long it is.
wolffd@0 19 description = ''; % text displayed when you click on the node
wolffd@0 20 curvature = [1 1]; % curvature of the node, [1,1] = circle
wolffd@0 21 lineStyle = '-'; % line style for the node
wolffd@0 22 lineWidth = 2; % line wdth for the node
wolffd@0 23 inedges = []; % indices of edges in
wolffd@0 24 outedges = []; % indices of edges out
wolffd@0 25 fontSize = 12; % The font size for the node
wolffd@0 26 showFullLabel = false; % If true, node labels are not split onto multiple lines regardelss of how long
wolffd@0 27 end
wolffd@0 28
wolffd@0 29 properties
wolffd@0 30 % Color properties
wolffd@0 31 lineColor = 'k'; % line color for the node
wolffd@0 32 selectedColor = [1 1 0.7]; % face color when selected with mouse
wolffd@0 33 faceColor = [1 1 0.8]; % face color when not shaded
wolffd@0 34 shadedColor = 'r'; % color when shaded, call shade() to shade
wolffd@0 35 textColor = 'k'; % label's text color
wolffd@0 36 containingGraph = []; % containing graph object
wolffd@0 37
wolffd@0 38 end
wolffd@0 39
wolffd@0 40 properties(GetAccess = 'public', SetAccess = 'protected')
wolffd@0 41 % Read only properties
wolffd@0 42 xpos = 0; % x-coordinate of node center relative to parent axes
wolffd@0 43 ypos = 0; % y-coordinate of node center relative to parent axes
wolffd@0 44 isvisible = false; % true iff the node is being displayed
wolffd@0 45 isshaded = false; % is the node shaded or not?
wolffd@0 46 width = 1; % width in data units
wolffd@0 47 height = 1; % height in data units
wolffd@0 48 end
wolffd@0 49
wolffd@0 50 properties(GetAccess = 'public', SetAccess = 'protected')
wolffd@0 51 % Handles to underlying Matlab graphics objects
wolffd@0 52 rechandle = []; % handle to the underlying rectangle object
wolffd@0 53 labelhandle = []; % handle to the underlying text object
wolffd@0 54 parent = []; % handle to the parent axes object
wolffd@0 55 isselected = false; % true iff, the node has been selected
wolffd@0 56 end
wolffd@0 57
wolffd@0 58 methods
wolffd@0 59
wolffd@0 60 function obj = graphViz4MatlabNode(label)
wolffd@0 61 % Node Constructor
wolffd@0 62 obj.label = label;
wolffd@0 63 obj.setSplitLabel(label);
wolffd@0 64
wolffd@0 65 end
wolffd@0 66
wolffd@0 67 function draw(obj,parent)
wolffd@0 68 % Draw the node on the specified parent axes. If no parent is
wolffd@0 69 % specified, the current axis is used.
wolffd@0 70 if(obj.isvisible)
wolffd@0 71 warning('GRAPHNODE:draw',['Node ',obj.label,' is already drawn, call redraw().']);
wolffd@0 72 return;
wolffd@0 73 end
wolffd@0 74 if(nargin < 2)
wolffd@0 75 if(isempty(obj.parent) || ~ishandle(obj.parent))
wolffd@0 76 obj.parent = gca;
wolffd@0 77 end
wolffd@0 78 else
wolffd@0 79 obj.parent = parent;
wolffd@0 80 end
wolffd@0 81 obj.drawNode();
wolffd@0 82 obj.setText();
wolffd@0 83 obj.isvisible = true;
wolffd@0 84 end
wolffd@0 85
wolffd@0 86 function redraw(obj)
wolffd@0 87 % Redraw the node, (must be called after node properties are
wolffd@0 88 % changed).
wolffd@0 89 if(obj.isvisible), obj.erase;end
wolffd@0 90 obj.draw();
wolffd@0 91 end
wolffd@0 92
wolffd@0 93 function erase(obj)
wolffd@0 94 % Erase the node but do not delete it
wolffd@0 95 if(~obj.isvisible)
wolffd@0 96 warning('GRAPHNODE:erase',['Node ',obj.label,' is already erased']);
wolffd@0 97 return;
wolffd@0 98 end
wolffd@0 99 delete(obj.rechandle);
wolffd@0 100 delete(obj.labelhandle);
wolffd@0 101 obj.rechandle = [];
wolffd@0 102 end
wolffd@0 103
wolffd@0 104 function shade(obj,color)
wolffd@0 105 % Shade the node the specified color. The default color is used if
wolffd@0 106 % none given.
wolffd@0 107 obj.isshaded = true;
wolffd@0 108 if(nargin == 2)
wolffd@0 109 obj.shadedColor = color;
wolffd@0 110 end
wolffd@0 111 if(obj.isvisible)
wolffd@0 112 set(obj.rechandle,'FaceColor',obj.shadedColor);
wolffd@0 113 end
wolffd@0 114 end
wolffd@0 115
wolffd@0 116 function unshade(obj)
wolffd@0 117 % Unshade the node
wolffd@0 118 obj.isshaded = false;
wolffd@0 119 if(obj.isvisible)
wolffd@0 120 set(obj.rechandle,'FaceColor',obj.faceColor);
wolffd@0 121 end
wolffd@0 122 end
wolffd@0 123
wolffd@0 124 function resize(obj,width,height)
wolffd@0 125 % Resize the node by the specified proportion
wolffd@0 126 if(nargin < 3)
wolffd@0 127 if(~isempty(obj.containingGraph))
wolffd@0 128 height = width;
wolffd@0 129 end
wolffd@0 130 end
wolffd@0 131 obj.width = width;
wolffd@0 132 obj.height = height;
wolffd@0 133 if(obj.isvisible), obj.redraw; end
wolffd@0 134 end
wolffd@0 135
wolffd@0 136 function move(obj,x,y)
wolffd@0 137 % Move the node's center to the new x,y coordinates, (relative to
wolffd@0 138 % the parent axes.)
wolffd@0 139 obj.xpos = x; obj.ypos = y;
wolffd@0 140 if(obj.isvisible),obj.redraw;end
wolffd@0 141 end
wolffd@0 142
wolffd@0 143 function select(obj)
wolffd@0 144 % Call this function to set the node in a selected state.
wolffd@0 145 obj.isselected = true;
wolffd@0 146 if(obj.isvisible)
wolffd@0 147 set(obj.rechandle,'faceColor',obj.selectedColor);
wolffd@0 148 end
wolffd@0 149 end
wolffd@0 150
wolffd@0 151
wolffd@0 152 function deselect(obj)
wolffd@0 153 % Call this function to deselect the node.
wolffd@0 154 obj.isselected = false;
wolffd@0 155 if(obj.isvisible)
wolffd@0 156 obj.redraw;
wolffd@0 157 end
wolffd@0 158 end
wolffd@0 159
wolffd@0 160 end % end of public methods
wolffd@0 161
wolffd@0 162 methods(Access = 'protected')
wolffd@0 163
wolffd@0 164 function nodePressed(obj,varargin)
wolffd@0 165 % This function is called whenever the node is pressed.
wolffd@0 166 if(~isempty(obj.containingGraph))
wolffd@0 167 obj.containingGraph.nodeSelected(obj);
wolffd@0 168 end
wolffd@0 169 end
wolffd@0 170
wolffd@0 171 function nodeDeleted(obj)
wolffd@0 172 % This function is called whenver the node is deleted, (perhaps
wolffd@0 173 % because the figure window was closed for instance).
wolffd@0 174 obj.isvisible = false;
wolffd@0 175 obj.parent = [];
wolffd@0 176 end
wolffd@0 177
wolffd@0 178 function drawNode(obj)
wolffd@0 179 % Draw the actual node
wolffd@0 180 recxpos = obj.xpos - obj.width/2;
wolffd@0 181 recypos = obj.ypos - obj.height/2;
wolffd@0 182 lineColor = obj.lineColor;
wolffd@0 183 lineWidth = obj.lineWidth;
wolffd@0 184 if(obj.isselected)
wolffd@0 185 color = obj.selectedColor;
wolffd@0 186 lineColor = 'r';
wolffd@0 187 lineWidth = 1.5*lineWidth;
wolffd@0 188 elseif(obj.isshaded)
wolffd@0 189 color = obj.shadedColor;
wolffd@0 190 else
wolffd@0 191 color = obj.faceColor;
wolffd@0 192 end
wolffd@0 193 obj.rechandle = rectangle(...
wolffd@0 194 'Parent' ,obj.parent ,...
wolffd@0 195 'Position' ,[recxpos,recypos,obj.width,obj.height] ,...
wolffd@0 196 'Curvature' ,obj.curvature ,...
wolffd@0 197 'LineWidth' , lineWidth ,...
wolffd@0 198 'LineStyle' ,obj.lineStyle ,...
wolffd@0 199 'EdgeColor' ,lineColor ,...
wolffd@0 200 'faceColor' ,color ,...
wolffd@0 201 'DisplayName' ,obj.label ,...
wolffd@0 202 'Tag' ,obj.label ,...
wolffd@0 203 'ButtonDownFcn',@obj.nodePressed ,...
wolffd@0 204 'UserData' ,obj ,...
wolffd@0 205 'DeleteFcn' ,@(varargin)obj.nodeDeleted() );
wolffd@0 206 end
wolffd@0 207
wolffd@0 208 function setText(obj)
wolffd@0 209 % Draw the node's label
wolffd@0 210 if((length(obj.label) < 10) || obj.useFullLabel || obj.showFullLabel)
wolffd@0 211 label = obj.label;
wolffd@0 212 else
wolffd@0 213 label = obj.splitLabel;
wolffd@0 214 end
wolffd@0 215 obj.labelhandle = text(obj.xpos,obj.ypos,label ,...
wolffd@0 216 'FontUnits' , 'points' ,...
wolffd@0 217 'HitTest' , 'off' ,...
wolffd@0 218 'FontWeight' , 'demi' ,...
wolffd@0 219 'Margin' , 0.01 ,...
wolffd@0 220 'HorizontalAlignment' , 'center' ,...
wolffd@0 221 'BackGroundColor' , 'none' ,...
wolffd@0 222 'Selected' , 'off' ,...
wolffd@0 223 'VerticalAlignment' , 'middle' ,...
wolffd@0 224 'LineStyle' , 'none' ,...
wolffd@0 225 'FontSize' , obj.fontSize ,...
wolffd@0 226 'Color' , obj.textColor );
wolffd@0 227 if(obj.useFullLabel)
wolffd@0 228 set(obj.labelhandle,'BackgroundColor',obj.selectedColor,'Margin',6,'EdgeColor','k','LineStyle','-');
wolffd@0 229 end
wolffd@0 230 end
wolffd@0 231
wolffd@0 232 function resizeText(obj)
wolffd@0 233 % Resize the text to fill the node (too slow for large graphs)
wolffd@0 234 fontsize = obj.maxFontSize;
wolffd@0 235 set(obj.labelhandle,'FontSize',fontsize);
wolffd@0 236 extent = get(obj.labelhandle,'Extent');
wolffd@0 237
wolffd@0 238 while((extent(1) < (obj.xpos - obj.width/2)) || (extent(2)+(extent(4)) > (obj.ypos + obj.height/2)))
wolffd@0 239 fontsize = 0.95*fontsize;
wolffd@0 240 set(obj.labelhandle,'FontSize',fontsize);
wolffd@0 241 extent = get(obj.labelhandle,'Extent');
wolffd@0 242 end
wolffd@0 243 end
wolffd@0 244
wolffd@0 245 function setSplitLabel(obj,label)
wolffd@0 246
wolffd@0 247 obj.splitLabel = splitString(label,8,10);
wolffd@0 248
wolffd@0 249 end
wolffd@0 250
wolffd@0 251 end % end of protected methods
wolffd@0 252
wolffd@0 253 end % end of graphnode class
wolffd@0 254
wolffd@0 255
wolffd@0 256
wolffd@0 257
wolffd@0 258
wolffd@0 259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
wolffd@0 260 function S = splitString(varargin)
wolffd@0 261 % Split a string into multiple lines based on camel case.
wolffd@0 262 %
wolffd@0 263 % Inputs
wolffd@0 264 %
wolffd@0 265 % '-S' the string to split
wolffd@0 266 % '-minSize' does not split at all if length(S) < minSize
wolffd@0 267 % '-maxSize' splits no matter what, (even if no camel case change) if length(S) > maxSize
wolffd@0 268 % '-center' if true, [default], the string is center justified
wolffd@0 269 % '-cellMode' if true, a cell array of strings is returned, instead of a char array.
wolffd@0 270
wolffd@0 271 [S,minSize,maxSize,cellMode,center] = processArgs(varargin,'*+-S','','-minSize',8,'-maxSize',10,'-cellMode',false,'-center',true);
wolffd@0 272
wolffd@0 273 S = splitInTwo(S);
wolffd@0 274 if center
wolffd@0 275 S = strjust(S,'center');
wolffd@0 276 end
wolffd@0 277 if cellMode
wolffd@0 278 S = cellstr(S);
wolffd@0 279 end
wolffd@0 280
wolffd@0 281 function str = splitInTwo(str)
wolffd@0 282 % recursively split a string into two based on camel case
wolffd@0 283 isupper = isstrprop(str(2:end),'upper');
wolffd@0 284 if(size(str,2) >= minSize && any(isupper))
wolffd@0 285 first = find(isupper); first = first(1);
wolffd@0 286 top = str(1:first);
wolffd@0 287 bottom = str(first+1:end);
wolffd@0 288 str = strvcat(splitInTwo(top),splitInTwo(bottom)); %#ok
wolffd@0 289 elseif(size(str,2) > maxSize)
wolffd@0 290 top = [str(1:floor(length(str)/2)),'-'];
wolffd@0 291 bottom = str(floor(length(str)/2)+1:end);
wolffd@0 292 str = strvcat(splitInTwo(top),splitInTwo(bottom)); %#ok
wolffd@0 293 end
wolffd@0 294 end
wolffd@0 295 end
wolffd@0 296
wolffd@0 297
wolffd@0 298