Page Index Toggle Pages: [1] 2  Send TopicPrint
Hot Topic (More than 10 Replies) Magnifying glass or zoom window (Read 9323 times)
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Magnifying glass or zoom window
Apr 17th, 2012 at 12:23pm
Print Post  
Hi

We have several diagrams that have a very large number of nodes.  Our client has asked if we can provide a some sort of magnification facility that shows a zoomed in view of what is under the mouse cursor.  The idea is to allow the user to see the detail of the nodes without having to keep zooming in and out on the diagram as they tend to get lost when they do that.

Ideally this would be in the form of a magnifying glass type control acting as a mouse pointer, but I think that may be very involved, so instead I was wondering about creating a small secondary DiagramView that shows the diagram zoomed in at 100% and that updates what is displayed as the mouse pointer is moved (i.e. the view shown in the second diagramview is always centred on the mouse pointer in real time).  Any idea if that would work, and if so how I could go about syncing the mouse movement to the diagramview?

I am very open to better ideas if you have any!

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #1 - Apr 17th, 2012 at 1:27pm
Print Post  
Hi,

It could look like this:

Code
Select All
private DiagramNode zoomedNode;

private void diagramView_MouseMove(object sender, MouseEventArgs e)
{
	PointF mousePos = diagramView.ClientToDoc(e.Location);
	DiagramNode node = diagram.GetNodeAt(mousePos);
	if (node != zoomedNode)
	{
		zoomedNode = node;
		diagramView.Invalidate();
	}
}

private void ScaleAt(IGraphics graphics, PointF point, float scale)
{
	graphics.TranslateTransform(point.X, point.Y);
	graphics.ScaleTransform(scale, scale);
	graphics.TranslateTransform(-point.X, -point.Y);
}

private void diagram_DrawForeground(object sender, DiagramEventArgs e)
{
	if (diagramView.ZoomFactor >= 100)
		return;
	if (zoomedNode != null)
	{
		GraphicsState state = e.Graphics.Save();
		ScaleAt(e.Graphics,
			zoomedNode.GetCenter(), 100.0f / diagramView.ZoomFactor);
		zoomedNode.Draw(e.Graphics, new RenderOptions());
		e.Graphics.Restore(state);
	}
}
 



To make it fancier, you could draw all nodes at some distance from the current point at progressively decreasing scale factors - that should look like a fish-eye effect. If you implement that, please share the code Wink

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #2 - Apr 17th, 2012 at 2:09pm
Print Post  
Ooooo... fish-eye... interesting Smiley

Thanks Stoyan, I'll give it a go and see how I get on.
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #3 - Apr 17th, 2012 at 2:49pm
Print Post  
Hi Stoyan

That worked absolutely perfectly, thank you so much. 

To anyone looking at this thread later, the code above makes it so that whenever you mouse over a node, that node is displayed at 100% zoom, where as the rest of the diagram remains at it's original zoom level.  Effectively this magnifies just the node under the cursor.

The only other point to note is that the user can still click on the node 'under' the magnification, which is great, but if clicking on the node causes e.g. the back colour of the node to change, then you need to call diagramview.invalidate in the NodeClicked event too, otherwise you may get some partial painting on the node.

Thanks again  Smiley
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #4 - Apr 17th, 2012 at 5:43pm
Print Post  
And inevitably the next question from the client was: Is there any way to achieve a similar thing with magnifying the diagram labels?

Do I need to somehow convert the link's label to a node and then it could work with the existing code? I remember seeing some code once upon a time to do that I think?

« Last Edit: Apr 17th, 2012 at 10:07pm by tom_w »  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #5 - Apr 18th, 2012 at 6:16am
Print Post  
If the item under the mouse pointer is a link, you could call e.Graphics.DrawString to draw its label while the same scale transform is applied. Alternatively, draw both the link and the nodes it connects magnified by calling zoomedLink.Draw(), zoomedLink.Origin.Draw() and zoomedLink.Destination.Draw().

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #6 - Apr 18th, 2012 at 11:02am
Print Post  
I tried the e.Graphics.DrawString approach but just kept getting a big red cross instead of the diagram - I'm fairly clueless when it comes to graphics stuff though.

I got the zoomedLink.Draw() approach working - thank you for that. The only issue is that because the link text background is transparent it all ends up looking a bit messy, as the zoomed image of the link and the zoomed link text are overlaid on top of the original text and origin/destination nodes (depending on the zoom level).

Is there anyway I can set a background fill on the label text, or on the zoomed region?
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #7 - Apr 18th, 2012 at 2:19pm
Print Post  
The following code will clear 1-cm wide region around painted link and nodes to hide the background. Instead of using BackBrush, you could paint it using a semi-transparent color to fade out the background.

I hope that helps,
Stoyan

Code
Select All
private DiagramItem zoomedItem;

private void diagramView_MouseMove(object sender, MouseEventArgs e)
{
	PointF mousePos = diagramView.ClientToDoc(e.Location);
	DiagramItem item = diagram.GetItemAt(mousePos, false);
	if (item != zoomedItem)
	{
		zoomedItem = item;
		diagramView.Invalidate();
	}
}

private void ScaleAt(IGraphics graphics, PointF point, float scale)
{
	graphics.TranslateTransform(point.X, point.Y);
	graphics.ScaleTransform(scale, scale);
	graphics.TranslateTransform(-point.X, -point.Y);
}

PointF GetCenter(RectangleF r)
{
	return new PointF(r.X + r.Width / 2, r.Y + r.Height / 2);
}

private void diagram_DrawForeground(object sender, DiagramEventArgs e)
{
	if (zoomedItem == null || diagramView.ZoomFactor >= 100)
		return;

	DiagramNode zoomedNode = zoomedItem as DiagramNode;
	if (zoomedNode != null)
	{
		GraphicsState state = e.Graphics.Save();
		ScaleAt(e.Graphics,
			zoomedNode.GetCenter(), 100.0f / diagramView.ZoomFactor);
		zoomedNode.Draw(e.Graphics, new RenderOptions());
		e.Graphics.Restore(state);
	}

	DiagramLink zoomedLink = zoomedItem as DiagramLink;
	if (zoomedLink != null)
	{
		GraphicsState state = e.Graphics.Save();
		ScaleAt(e.Graphics,
			GetCenter(zoomedLink.GetBounds()), 100.0f / diagramView.ZoomFactor);

		// fill the region around painted items to hide background details
		GraphicsPath path = new GraphicsPath(FillMode.Winding);
		path.AddPolygon(zoomedLink.GetOutlinePoly(false).GetArray());
		path.AddPolygon(zoomedLink.Origin.GetOutlinePoly(false).GetArray());
		path.AddPolygon(zoomedLink.Destination.GetOutlinePoly(false).GetArray());
		path.Widen(new System.Drawing.Pen(Color.White, 10));

		System.Drawing.Brush brush = diagram.BackBrush.CreateGdiBrush(diagram.Bounds);
		e.Graphics.FillPath(brush, path);
		brush.Dispose();

		// render the link and its nodes
		RenderOptions renderOptions = new RenderOptions();
		zoomedLink.Draw(e.Graphics, renderOptions);
		zoomedLink.Origin.Draw(e.Graphics, renderOptions);
		zoomedLink.Destination.Draw(e.Graphics, renderOptions);

		e.Graphics.Restore(state);
	}
}
 

  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #8 - Apr 18th, 2012 at 5:26pm
Print Post  
That's a fantastic solution Stoyan, it works perfectly.  Thank you so much  Smiley
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #9 - Apr 18th, 2012 at 7:11pm
Print Post  
Here's even more fantastic one Wink you could also add some code to draw a frame around the circle to make it look like a real magnifying glass...

Code
Select All
private void diagramView_MouseMove(object sender, MouseEventArgs e)
{
	if (zoomMode)
		diagramView.Invalidate();
}

private void ScaleAt(IGraphics graphics, PointF point, float scale)
{
	graphics.TranslateTransform(point.X, point.Y);
	graphics.ScaleTransform(scale, scale);
	graphics.TranslateTransform(-point.X, -point.Y);
}

private void diagram_DrawForeground(object sender, DiagramEventArgs e)
{
	if (!zoomMode || diagramView.ZoomFactor >= 100)
		return;

	PointF center = diagramView.ClientToDoc(
		diagramView.PointToClient(MousePosition));
	RectangleF zoomRect = new RectangleF(
		center.X - 20, center.Y - 20, 40, 40);
	diagram.DrawForeground -= diagram_DrawForeground; // otherwise diagram.Draw will cause recursion

	GraphicsState state = e.Graphics.Save();
	ScaleAt(e.Graphics, center, 100.0f / diagramView.ZoomFactor);

	GraphicsPath clip = new GraphicsPath();
	clip.AddEllipse(zoomRect);
	e.Graphics.SetClip(clip);

	diagram.Draw(e.Graphics, new RenderOptions(), zoomRect, true);

	e.Graphics.Restore(state);

	diagram.DrawForeground += diagram_DrawForeground;
}
 

  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #10 - Apr 18th, 2012 at 9:05pm
Print Post  
That is so cool, I've just spent ten minutes magnifying things and being absolutely transfixed by it!


Stoyo wrote on Apr 18th, 2012 at 7:11pm:
you could also add some code to draw a frame around the circle to make it look like a real magnifying glass...


Hmmm... you'd think wouldn't you!  I really have a very limited grasp of how direct drawing to graphics objects work I'm afraid.  Databases I understand, graphics less so!

This code deserves adding into the flowchart.net controls, it must be something lots of people could benefit from?
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #11 - Apr 19th, 2012 at 10:32am
Print Post  
It won't be fun to draw a realistic frame using only GDI calls anyway. If you really need it, you can use a transparent PNG image of a frame and render it by calling e.Graphcs.DrawImage(img, zoomRect). We'll see about adding it as a built-in feature, perhaps a Behavior.Magnify member that will only allow zooming around...

Stoyan
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #12 - Apr 19th, 2012 at 10:54am
Print Post  
I think it's great as it is, although the png idea is interesting, it would mean the designers could produce something nice that goes with the rest of the look and feel.  If you do add it to the main code then allowing the developer to set the png will probably save you a lot of requests for tweaking the presentation too.

The Behaviour idea is a really good one, it only really makes sense to use the above with the DoNothing behaviour, or in some sort of manually implemented read-only mode - the magnifier graphics get very confused if you start trying to draw links or resize nodes.

For editable diagrams I think we will have a toggle button for turning the magnifier on, which then sets the diagram behaviour to DoNothing. I may make this mode switch on automatically when they zoom out past a certain point too as once the node text is unreadable there is no real sense in being able to edit the diagram.

Sorry, thinking out loud! Thanks again for all of your help on this, it is a far nicer solution that I'd imagined would be possible.
  
Back to top
 
IP Logged
 
tom_w
Junior Member
**
Offline


Swimlanes made our dreams
come true :-)

Posts: 79
Joined: Oct 20th, 2008
Re: Magnifying glass or zoom window
Reply #13 - Apr 23rd, 2012 at 11:38am
Print Post  
Hi

Is there any way to get the magnifier to work on the lane headers on a swimlane diagram?

(on a similar note, is there anyway to get the Lanes to show in the diagram Overview control?)
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Magnifying glass or zoom window
Reply #14 - Apr 24th, 2012 at 7:47pm
Print Post  
Change the diagram.Draw call to the following to also draw the lanes:

RenderOptions options = new RenderOptions();
options.VisibleRect = zoomRect;
diagram.Draw(e.Graphics, options, zoomRect, true);

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: [1] 2 
Send TopicPrint