Mercurial > hg > camir-aes2014
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolboxes/graph_visualisation/graphViz4Matlab/util/graphViz4MatlabNode.m Tue Feb 10 15:05:51 2015 +0000 @@ -0,0 +1,298 @@ +classdef graphViz4MatlabNode < dynamicprops & hgsetget +% This class represents a drawable node in an arbitrary graph. +% +% Public properties can be set using the standard Matlab set method as in +% set(node,'curvature',[0,0],'linesytle','--','linecolor','g'). Call +% node.redraw to redraw it after changing properties. +% +% Nodes are not really designed to live on their own, they should be +% aggregated into a graph object responsible for layout. +% +% Matthew Dunham +% University of British Columbia +% http://www.cs.ubc.ca/~mdunham/ + + properties + label; % displayed name for the node + splitLabel; % label split in the middle + useFullLabel = false; % if true, the full non-split label is used regardles of how long it is. + description = ''; % text displayed when you click on the node + curvature = [1 1]; % curvature of the node, [1,1] = circle + lineStyle = '-'; % line style for the node + lineWidth = 2; % line wdth for the node + inedges = []; % indices of edges in + outedges = []; % indices of edges out + fontSize = 12; % The font size for the node + showFullLabel = false; % If true, node labels are not split onto multiple lines regardelss of how long + end + + properties + % Color properties + lineColor = 'k'; % line color for the node + selectedColor = [1 1 0.7]; % face color when selected with mouse + faceColor = [1 1 0.8]; % face color when not shaded + shadedColor = 'r'; % color when shaded, call shade() to shade + textColor = 'k'; % label's text color + containingGraph = []; % containing graph object + + end + + properties(GetAccess = 'public', SetAccess = 'protected') + % Read only properties + xpos = 0; % x-coordinate of node center relative to parent axes + ypos = 0; % y-coordinate of node center relative to parent axes + isvisible = false; % true iff the node is being displayed + isshaded = false; % is the node shaded or not? + width = 1; % width in data units + height = 1; % height in data units + end + + properties(GetAccess = 'public', SetAccess = 'protected') + % Handles to underlying Matlab graphics objects + rechandle = []; % handle to the underlying rectangle object + labelhandle = []; % handle to the underlying text object + parent = []; % handle to the parent axes object + isselected = false; % true iff, the node has been selected + end + + methods + + function obj = graphViz4MatlabNode(label) + % Node Constructor + obj.label = label; + obj.setSplitLabel(label); + + end + + function draw(obj,parent) + % Draw the node on the specified parent axes. If no parent is + % specified, the current axis is used. + if(obj.isvisible) + warning('GRAPHNODE:draw',['Node ',obj.label,' is already drawn, call redraw().']); + return; + end + if(nargin < 2) + if(isempty(obj.parent) || ~ishandle(obj.parent)) + obj.parent = gca; + end + else + obj.parent = parent; + end + obj.drawNode(); + obj.setText(); + obj.isvisible = true; + end + + function redraw(obj) + % Redraw the node, (must be called after node properties are + % changed). + if(obj.isvisible), obj.erase;end + obj.draw(); + end + + function erase(obj) + % Erase the node but do not delete it + if(~obj.isvisible) + warning('GRAPHNODE:erase',['Node ',obj.label,' is already erased']); + return; + end + delete(obj.rechandle); + delete(obj.labelhandle); + obj.rechandle = []; + end + + function shade(obj,color) + % Shade the node the specified color. The default color is used if + % none given. + obj.isshaded = true; + if(nargin == 2) + obj.shadedColor = color; + end + if(obj.isvisible) + set(obj.rechandle,'FaceColor',obj.shadedColor); + end + end + + function unshade(obj) + % Unshade the node + obj.isshaded = false; + if(obj.isvisible) + set(obj.rechandle,'FaceColor',obj.faceColor); + end + end + + function resize(obj,width,height) + % Resize the node by the specified proportion + if(nargin < 3) + if(~isempty(obj.containingGraph)) + height = width; + end + end + obj.width = width; + obj.height = height; + if(obj.isvisible), obj.redraw; end + end + + function move(obj,x,y) + % Move the node's center to the new x,y coordinates, (relative to + % the parent axes.) + obj.xpos = x; obj.ypos = y; + if(obj.isvisible),obj.redraw;end + end + + function select(obj) + % Call this function to set the node in a selected state. + obj.isselected = true; + if(obj.isvisible) + set(obj.rechandle,'faceColor',obj.selectedColor); + end + end + + + function deselect(obj) + % Call this function to deselect the node. + obj.isselected = false; + if(obj.isvisible) + obj.redraw; + end + end + + end % end of public methods + + methods(Access = 'protected') + + function nodePressed(obj,varargin) + % This function is called whenever the node is pressed. + if(~isempty(obj.containingGraph)) + obj.containingGraph.nodeSelected(obj); + end + end + + function nodeDeleted(obj) + % This function is called whenver the node is deleted, (perhaps + % because the figure window was closed for instance). + obj.isvisible = false; + obj.parent = []; + end + + function drawNode(obj) + % Draw the actual node + recxpos = obj.xpos - obj.width/2; + recypos = obj.ypos - obj.height/2; + lineColor = obj.lineColor; + lineWidth = obj.lineWidth; + if(obj.isselected) + color = obj.selectedColor; + lineColor = 'r'; + lineWidth = 1.5*lineWidth; + elseif(obj.isshaded) + color = obj.shadedColor; + else + color = obj.faceColor; + end + obj.rechandle = rectangle(... + 'Parent' ,obj.parent ,... + 'Position' ,[recxpos,recypos,obj.width,obj.height] ,... + 'Curvature' ,obj.curvature ,... + 'LineWidth' , lineWidth ,... + 'LineStyle' ,obj.lineStyle ,... + 'EdgeColor' ,lineColor ,... + 'faceColor' ,color ,... + 'DisplayName' ,obj.label ,... + 'Tag' ,obj.label ,... + 'ButtonDownFcn',@obj.nodePressed ,... + 'UserData' ,obj ,... + 'DeleteFcn' ,@(varargin)obj.nodeDeleted() ); + end + + function setText(obj) + % Draw the node's label + if((length(obj.label) < 10) || obj.useFullLabel || obj.showFullLabel) + label = obj.label; + else + label = obj.splitLabel; + end + obj.labelhandle = text(obj.xpos,obj.ypos,label ,... + 'FontUnits' , 'points' ,... + 'HitTest' , 'off' ,... + 'FontWeight' , 'demi' ,... + 'Margin' , 0.01 ,... + 'HorizontalAlignment' , 'center' ,... + 'BackGroundColor' , 'none' ,... + 'Selected' , 'off' ,... + 'VerticalAlignment' , 'middle' ,... + 'LineStyle' , 'none' ,... + 'FontSize' , obj.fontSize ,... + 'Color' , obj.textColor ); + if(obj.useFullLabel) + set(obj.labelhandle,'BackgroundColor',obj.selectedColor,'Margin',6,'EdgeColor','k','LineStyle','-'); + end + end + + function resizeText(obj) + % Resize the text to fill the node (too slow for large graphs) + fontsize = obj.maxFontSize; + set(obj.labelhandle,'FontSize',fontsize); + extent = get(obj.labelhandle,'Extent'); + + while((extent(1) < (obj.xpos - obj.width/2)) || (extent(2)+(extent(4)) > (obj.ypos + obj.height/2))) + fontsize = 0.95*fontsize; + set(obj.labelhandle,'FontSize',fontsize); + extent = get(obj.labelhandle,'Extent'); + end + end + + function setSplitLabel(obj,label) + + obj.splitLabel = splitString(label,8,10); + + end + + end % end of protected methods + +end % end of graphnode class + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function S = splitString(varargin) +% Split a string into multiple lines based on camel case. +% +% Inputs +% +% '-S' the string to split +% '-minSize' does not split at all if length(S) < minSize +% '-maxSize' splits no matter what, (even if no camel case change) if length(S) > maxSize +% '-center' if true, [default], the string is center justified +% '-cellMode' if true, a cell array of strings is returned, instead of a char array. + + [S,minSize,maxSize,cellMode,center] = processArgs(varargin,'*+-S','','-minSize',8,'-maxSize',10,'-cellMode',false,'-center',true); + + S = splitInTwo(S); + if center + S = strjust(S,'center'); + end + if cellMode + S = cellstr(S); + end + + function str = splitInTwo(str) + % recursively split a string into two based on camel case + isupper = isstrprop(str(2:end),'upper'); + if(size(str,2) >= minSize && any(isupper)) + first = find(isupper); first = first(1); + top = str(1:first); + bottom = str(first+1:end); + str = strvcat(splitInTwo(top),splitInTwo(bottom)); %#ok + elseif(size(str,2) > maxSize) + top = [str(1:floor(length(str)/2)),'-']; + bottom = str(floor(length(str)/2)+1:end); + str = strvcat(splitInTwo(top),splitInTwo(bottom)); %#ok + end + end +end + + +