Drag and Twist Photo Album

by Bron Skinner 2. September 2009 01:08

Drag and Twist Photo Album

 

I took up Silverlight almost a year ago and I can still remember one of the first projects someone else had posted on the Microsoft’s Silverlight Show that really sparked my interest in the technology - A Twist and Drag photo album. In searching the net for specific examples I found it very difficult to find any in depth descriptions of methodologies used to emulate what I had seen. So with a bit of elbow grease and determination I went at my notebook and came up with the following.

 

I think it's important to note that I originally wrote this article for www.meanbyte.com. You should check it out =D !

 

The BoxView Control

 

The image (media) that we will be manipulating will be contained within a BoxView Control. This container element exposes a number of properties that store important values used to calculate the particular object’s move-ability (twist, drag, and scale).

 

public int zIndex;

public double aScale, aTransX, aTransY, aAngle;

public Point centerPoint, lastPoint, lastCenterPoint;

 

We store the last set ZIndex value, ScaleTransform, TranslateTransform (Canvas.Left/TopProperty), and RotateTransform values. As well, we store the last calculated center point, the current center point, and the last point (mouse capture point used in the control’s Scale and Rotate calculation). We’ll dive into these a bit later.

 

Other than that, the BoxView control contains a Canvas and a few other controls used to spruce up the display of an Image or MediaElement etc.

Meanbyte Silverlight Photo Album

 

 

The Application (App.xaml)

 

For each Image (MediaElement) we add a BoxView control to our Application’s root UIElement (LayoutRoot).

 

A couple of properties are exposed off of the Main App:

 

private bool isDragging, isRotating;

private Point offset, currentPoint;

 

These allows us to determine if a BoxView is already being dragged/rotated and is interactable as well as storing the last MouseCapture points for the current BoxView that is being dragged (offset, currentPoint).

 

The actual control manipulation takes place in a single function…

 

private void renderTransformation(BoxView senderBoxView, double translateX, double translateY, double rotateAngle, double scale)

 

… that we call whenever we wish to update the X/Y Axis position of or RotateTransform or ScaleTransform properties of a BoxView. We’ll see this in action a little later.

 

Drag (Translate)

 

The first obstacle to tackle was the easiest, dragging objects. Silverlight has some built in functionality that allows us to accomplish this with relative ease.

 

There are two methods that I found in my initial thinking that would serve us well to translate the BoxView control over our application. We could employ a TranslateTranform or we could set the control’s Canvas.LeftProperty and Canvas.TopProperty. In testing both methods I found that since our dragging motion is procured through a continually updated lastpoint/currentpoint calculation over a mouse drag movement every few milliseconds using the TranslateTransform method proved a bit sluggish. Updating the Canvas.Left/TopProperty values to move the BoxViews was much smoother.

 

Do do this we must capture a few events – MouseDown on our BoxView, MouseUp on our BoxView, and MouseDrag while MouseDown on our BoxView.

 

On our Application’s LayoutRoot I’ve added three Event Handlers (which we attach to each child BoxView).

 

protected void BoxView_Drag_MouseDown(object sender, MouseButtonEventArgs e)

        {

            isDragging = true;

            isRotating = false;

            Canvas senderLayoutRoot = (Canvas)parentCanvas.Parent as Canvas;

            BoxView senderBoxView = (BoxView)sender as BoxView;

            senderBoxView.CaptureMouse();

            offset = e.GetPosition(senderBoxView);

            selectBoxView(senderBoxView);

        }

 

        protected void BoxView_Drag_MouseUp(object sender, MouseButtonEventArgs e)

        {

            isDragging = false;

            BoxView senderBoxView = (BoxView)sender as BoxView;

            senderBoxView.ReleaseMouseCapture();

        }

 

        protected void BoxView_Drag_MouseMove(object sender, MouseEventArgs e)

        {

            if (isDragging)

            {

                BoxView senderBoxView = (BoxView)sender as BoxView;

                Point newPosition = e.GetPosition(senderBoxView);

 renderTransformation(senderBoxView, (newPosition.X - offset.X),

(newPosition.Y - offset.Y), 0, senderBoxView.aScale, false);

 

                double centerX = (senderBoxView.aTransX + (senderBoxView.Width / 2));

                double centerY = (senderBoxView.aTransY + (senderBoxView.Height / 2));

                senderBoxView.centerPoint = new Point(centerX, centerY);

            }

        }

 

When we click on a BoxView we fire the BoxView_Drag_MouseDown handler which sets the main app’s isDragging to true and isRotating to false (above). This dissallows the application from calling our renderTransformation when unwanted. We also call the senderBoxView.CaptureMouse();.  A side note, we could clean up our code and utilize the CaptureMouse bool value for each BoxView instead of the isDragging property to determine interactability, however we need to distinguish between mouse capture for dragging purposes and mouse capture for rotating purposes. We also set the offset Point property for our App to the current mouse position (more about the MouseEventArgs.GetPosition() function below).

 

When we release the mouse on a BoxView we fire the BoxView_Drag_MouseUp handler which releases the mouse capture and sets our isDragging property back to false.

 

When we Move the mouse while isDragging is set to true (click and move the mouse before releasing it), we fire the BoxView_Drag_MouseMove handler which does each of three things:

 

1.     We employ the MouseEventArgs(e).GetPosition(UIElement); function that gets the Point data for the mouse location relative to a Parent UIElement.

 

Point newPosition = e.GetPosition(ParentElement);

 

2.     We employ the renderTransform function passing the selected BoxView so we know what to update, the difference between the offset (original mousecapture point) and the newPosition (current mousecapture point) or total X/Y distances to effectively translate:

 

(newPosition.X - offset.X), (newPosition.Y - offset.Y)

 

Note that our offset position is set with each new MouseDown event fire.

 

3.     We update the current centerpoint for the BoxView (used to calculate the scale/rotate properties of the BoxView for Twist/Rotate actions). We’ll look into this shortly.

 

It’s pertinant to note that we also call a selectBox() function that iterates through each BoxView control within our LayoutRoot and resets their ZIndex properties so that the selected BoxView remains on top.

 

private void selectBoxView(BoxView selectedBoxView)

        {

              for (int i = 0; i < LayoutRoot.Children.Count; i++)

              {

                     if (LayoutRoot.Children[i].GetType == typeOf(BoxView))

                     {

                           BoxView boxview = (BoxView)LayoutRoot.Children[i];

                           if (boxview.zIndex >= selectedBoxView.zIndex)

                           {

                                  if (boxview.zIndex <= 1)

                           {

                                  boxview.zIndex = 2;

                           }

                           else

                           {

                                  boxview.zIndex--;

                           }

}

boxview.SetValue(Canvas.ZIndexProperty, boxview.zIndex);

}

//numboxview set when controls added originally (total num boxviews)

selectedBoxView.zIndex = numBoxView + 1;

              selectedBoxView.SetValue(Canvas.ZIndexProperty, numBoxView + 1);

       }

 

The RenderTransformation Function

 

The renderTransform sets the appropriate values for the BoxView’s TransformGroup children (Rotate/Scale) as well as sets the Canvas.Top/LeftProperty values. Note the BoxView properties we’re updating as well (aScale, aTransX, and aTransY). These properties store the last value used to update the (actual)Scale.X/Yand (actual)Translate.X/Y values which maintains greater consistency in historical movement data rather than relying on methods like DependancyObject.GetValue(); which can return unexpected data as manipulation to these properties can occur autonomously.

 

private void renderTransformation(BoxView senderBoxView, double translateX, double translateY, double rotateAngle, double scale)

        {

            TransformGroup tg_senderBoxView = (TransformGroup)senderBoxView.LayoutRoot.RenderTransform;

            TranslateTransform tt_senderBoxView = (TranslateTransform)tg_senderBoxView.Children[0];

            RotateTransform rt_senderBoxView = (RotateTransform)tg_senderBoxView.Children[1];

            ScaleTransform st_senderBoxView = (ScaleTransform)tg_senderBoxView.Children[2];

 

            rt_senderBoxView.Angle += rotateAngle;

            senderBoxView.SetValue(Canvas.LeftProperty, (senderBoxView.aTransX + translateX));

            senderBoxView.SetValue(Canvas.TopProperty, (senderBoxView.aTransY + translateY));

           

 

            st_senderBoxView.ScaleX = scale;

            st_senderBoxView.ScaleY = scale;

            senderBoxView.aScale = scale;

            senderBoxView.aTransX = (double)senderBoxView.GetValue(Canvas.LeftProperty);

            senderBoxView.aTransY = (double)senderBoxView.GetValue(Canvas.TopProperty);

            senderBoxView.UpdateLayout();

        }

 

Twist (Rotate)

 

Now we get to the good stuff.

 

Much like the BoxView_Drag_MouseMove function discussed before, a BoxView_Rotate_MouseMove function allows for similair calculation and manipulation of our BoxView controls in a circular motion.

 

Observe the following diagram:

 

 Meanbyte Silverlight Photo Album

 

In the above, we use the Inverse Tangent function to calculate the two angles (la and ca). We calculate the each angle (lastAngle and currentAngle) and subtract the last from current to get the new total RotateAngle value. To get the angle we use the following equation:

 

Tan α = Opposite/Adjacent

 

To get our Opposite and Adjacent side lengths we use values we know, Point coordinates. We know our BoxView centerPoint as well as the current mouse point and last (drag motion start) mouse point.

 

Note that the Tan α will result in a Radian value. RotateTransforms take a double angle input value and so we must convert our Radian value to degrees using the following:

 

double degrees = radians * (180 / Math.PI);

 

Scale

 

Our final calculation is our Scale. As our mouse drag motion moves outward or inward our BoxView control scales itself to keep our MouseCapture point aligned with our Cursor position.

 

Observe the following diagram:

Meanbyte Silverlight Photo Album

We’ll use Geometry to calculate the appropriate ScaleTransform value we should apply to our BoxView based on mouse movement. Using the Pythagoras theorem (a^2 + b^2) = c^2 we will calculate our C1 and C2 values (hypotenuses) and derive a percentage C2 is of C1 (newScale above).

 

In order to calculate our A1 and B1 values we will use what data we posses, Point data (p1 – p4), control width, current and last updated scale values.

 

Calculating A1 and B1 can be done using our controls base dimensions and last known scale transform value (aScale).

 

A1 = control.height * control.aScale;

B1 = control.width * control.aScale;

 

Calculating A2 and B2 can be done by measuring the distance from p4.X or p4.Y to the BoxView centerPoint.X or centerPoint.Y. The only catch to using point data here relies on our knowing where our currentPoint (p4 above) is in relation to our BoxView’s centerPoint. For this we use quadrants (q1q4) above to determine if we need to use the difference between p4.X and centerPoint.X or p4.Y and centerPoint.Y.

 

if (currentPoint.X >= senderBoxView.centerPoint.X && currentPoint.Y <senderBoxView.centerPoint.Y)

{

//-- We know that our cursor must be in quadrant 1

A2 = currentPoint.X - senderBoxView.centerPoint.X;

B2 = senderBoxView.centerPoint.Y - currentPoint.Y;

}

 

Once we have our A2 and B2 values we use the Pythagoras theorem to calculate the value of C2, however we must multiply this value by 2 as we’ve used a triangle twice as small to derive our C2 value (see purple line above.

 

Finally we use our newScale value and pass this to our renderTransformation() function to update our BoxView’s scale.

 

Conclusion and Notes

 

Creating a Twist and Drag Photo album isn’t all to difficult once it’s conceptully broken down. As with any project tweaking will be necessary. Personally I believe minor alterations to algorithms used within artistic applications can provide a more organic user experience which in my optinion is more impressionable.

 

To see a live example visit http://www.meanbyte.com/?slcid=portfolio.

 

Tags:

Technical

Comments

11/20/2009 1:40:47 AM #

Interesting article. You make some good points. Thank you again.

Dillards United Kingdom |

4/18/2010 8:19:41 PM #

I currently run a blog about Plus Size Womens, I think I will change to this blogengine system as it is a lot nicer than mine.

Plus Size Womens United Kingdom |

6/28/2010 9:57:32 PM #

good luck for me I was looking for this information for several months ago. Finally I got it all here.

outdoor swing sets United States |

6/28/2010 9:57:33 PM #

Having read the post, I have bookmarked your blog.

discount dinnerware sets United States |

6/28/2010 9:57:34 PM #

I have never seen such a great blog and allposts seem to be original.

coffee espresso machines United States |

6/28/2010 9:57:35 PM #

gr8 resrch bro�

hair color pictures United States |

6/28/2010 9:57:35 PM #

I don�t know If I said it already but this so good stuff keep up the good work.

salton yogurt maker United States |

6/28/2010 9:57:36 PM #

Hi. I read a few of your other posts and wanted to know if you would be interested in exchanging blogroll links?

asvab practice test United States |

6/28/2010 9:57:36 PM #

Wow! what an idea ! What a concept ! Beautiful .. Amazing �

pictures of haircuts United States |

6/28/2010 9:57:37 PM #

Wonderful article, thanks for putting this together! This is obviously one great post. Thanks for the valuable information and insights you have so provided here

herpes photos United States |

6/28/2010 9:57:38 PM #

Hello, I found your blog in a new directory of blogs. I dont know how your blog came up, must have been a typo, Your blog looks good. Have a nice day.

toy dog breeds United States |

6/28/2010 9:57:38 PM #

Your blog is so informative � keep up the good work!!!!

easy cooking recipes United States |

6/28/2010 9:57:39 PM #

Hi, I can�t understand how to add your site in my rss reader. Can you Help me, please

herpes simplex 1 United States |

6/28/2010 9:57:40 PM #

I feel strongly about it and love reading more on this topic. If possible, as you gain knowledge, would you mind updating your blog with extra information?

personalized dog tags United States |

6/28/2010 9:57:41 PM #

Hello, maybe this is off topic but anyway, i've been browsing around your site and it looks really really neat. I'm building a new blog and struggling to make it look good, everytime i touch something i mess it up. How hard was it to build your site? Could someone like me with no experience do it, and add family update pages without wrecking it every time?

occupational therapy schools United States |

6/28/2010 9:57:41 PM #

Hi there, I found your blog via Google while searching for first aid for a heart attack and your post looks very interesting for me.

stress fracture foot United States |

6/28/2010 9:57:42 PM #

I really appreciate what you�re doing here.

frontline plus cats United States |

6/28/2010 9:57:43 PM #

gr8 resrch bro�

physical therapy salary United States |

6/28/2010 9:57:43 PM #

What is captcha code?, pls provide me captcha code codes or plugin, Thanks in advance.

fleas on humans United States |

6/28/2010 9:57:44 PM #

You made some good points there. I did a search on the topic and found most people will agree with your blog.

scabies pictures United States |

6/28/2010 9:57:45 PM #

Great concepts on this website. It's rare these days to find websites with data you are seeking. I am happy I chanced on this webpage. I will certainly bookmark it or even register for your rss feeds simply to be updated on your new posts. Thank you!

what is blood pressure United States |

6/28/2010 9:57:45 PM #

Hello, maybe this is off topic but anyway, i've been browsing around your site and it looks really really neat. I'm building a new blog and struggling to make it look good, everytime i touch something i mess it up. How hard was it to build your site? Could someone like me with no experience do it, and add family update pages without wrecking it every time?

pictures of shingles United States |

6/28/2010 9:57:46 PM #

Keep working ,great job!

ibuprofen side effects United States |

6/28/2010 9:57:47 PM #

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon.

disorders anxiety United States |

6/28/2010 9:57:47 PM #

Wow! what an idea ! What a concept ! Beautiful .. Amazing �

pictures of ringworm United States |

6/28/2010 9:57:48 PM #

Your post is really amazing as it provide visitors with great knowledge.

psat practice test United States |

6/28/2010 9:57:49 PM #

So informative things are provided here,I really happy to read this post,I was just imagine about it and you provided me the correct information I really bookmark it,for further reading,So thanks for sharing the information.

smart water filter United States |

6/28/2010 9:57:49 PM #

Great concepts on this website. It's rare these days to find websites with data you are seeking. I am happy I chanced on this webpage. I will certainly bookmark it or even register for your rss feeds simply to be updated on your new posts. Thank you!

blood preasure United States |

6/28/2010 9:57:50 PM #

It sounds like you're creating problems yourself by trying to solve this issue instead of looking at why their is a problem in the first place.

filter pur water United States |

6/28/2010 9:57:51 PM #

Super-Duper site! I am loving it!! Will come back again - taking you feeds also, Thanks.

weight loss effects United States |

6/28/2010 9:57:52 PM #

Super-Duper site! I am loving it!! Will come back again - taking you feeds also, Thanks.

socks over knee United States |

6/28/2010 9:57:52 PM #

Hmmm interesting stuff

blood pressure side effects United States |

6/28/2010 9:57:53 PM #

I have a awesome sense of humor and I enjoy laughing the wacky of her jokes.

socks dress United States |

6/28/2010 9:57:56 PM #

Searching for this for some time now - i guess luck is more advanced than search engines

food dehydrator tray United States |

6/28/2010 9:57:57 PM #

thanks !! very helpful post!

homedics massage shiatsu United States |

6/28/2010 9:57:57 PM #

I usually don�t post in Blogs but your blog forced me to, amazing work.. beautiful �

massage chair ijoy United States |

6/28/2010 9:57:58 PM #

Hello. Great job. I did not expect this on a Wednesday. This is a great story. Thanks!

evening gown dress United States |

6/28/2010 9:57:59 PM #

found your site on del.icio.us today and really liked it.. i bookmarked it and will be back to check it out some more later ..

evening wedding dress United States |

6/28/2010 9:58:00 PM #

Your post is really amazing as it provide visitors with great knowledge.

dry face skin United States |

6/28/2010 9:58:01 PM #

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post

window coverings blinds United States |

6/28/2010 9:58:01 PM #

I enjoyed reading it. I need to read more on this topic...I admiring time and effort you put in your blog, because it is obviously one great place where I can find lot of useful info..

gold toe sock United States |

6/28/2010 9:58:02 PM #

Your post is really amazing as it provide visitors with great knowledge.

blinds for windows United States |

6/28/2010 9:58:03 PM #

Thank you for the insight, i really appreciate your posts.

lip gloss cosmetics United States |

6/28/2010 9:58:04 PM #

I really enjoyed reading through this write-up. I most certainly will be coming back to read some more intriguing ideas. Thank you.

women high heels United States |

6/28/2010 9:58:04 PM #

Well worth the read. thank you very much for taking the time to share with those who are starting on the subject. Greetings

folding table chairs United States |

6/28/2010 9:58:05 PM #

Interesting information. May I add this blog to my favorite ?

stockings high heels United States |

6/28/2010 9:58:06 PM #

Some interesting information, thank you! I'll refer my blog readers to this site

treatment of pain United States |

6/28/2010 9:58:07 PM #

Keep working ,great job!

makeup lighted mirror United States |

6/28/2010 9:58:07 PM #

For this matter, once I discussed with one of my friends, not only about the content you talked about, but also to how to improve and develop, but no results. So I am deeply moved by what you said today.

chlorine generation United States |

6/28/2010 9:58:08 PM #

I just want to say I like it and thanks.

pain management specialist United States |

6/28/2010 9:58:09 PM #

Of course, what a great site and informative posts, I will add backlink - bookmark this site? Regards, Reader.

lawn pest control United States |

6/28/2010 9:58:10 PM #

Thanks a lot for enjoying this beauty article with me.

joint pain causes United States |

6/28/2010 9:58:10 PM #

Thank you for your information. Such a very fine post.

garden pest control United States |

6/28/2010 9:58:11 PM #

I do not post on blogs, but I would like to say that this post really forced me to do so! really nice post.

causes back pain United States |

6/28/2010 9:58:12 PM #

What a great post. I have to say I really enjoyed reading it. Thanks!

knee high shoes United States |

6/28/2010 9:58:13 PM #

This is just the information I am finding everywhere. Thanks for your blog, I just subscribe your blog. This is a nice blog.

fishing boats sale United States |

6/28/2010 9:58:13 PM #

Oops! I should have shared this with you earlier, any ways it�s not so late.

lizlange maternity United States |

6/28/2010 9:58:14 PM #

You made some good points there. I did a search on the topic and found most people will agree with your blog.

bayi United States |

6/28/2010 9:58:15 PM #

Well, I just found your blog unexpectedly from the search engine. First time I saw it, I know it's a very informative blog. I got so many something new from here. Good work and thanks for that!

ring sling United States |

6/28/2010 9:58:16 PM #

Useful information shared..Iam very happy to read this article..thanks for giving us nice info.Fantastic walk-through. I appreciate this post

pouch sling United States |

6/28/2010 9:58:17 PM #

I have never seen such a great blog and allposts seem to be original.

perlengkapan bayi United States |

6/28/2010 9:58:18 PM #

I would like to thank you for the efforts you have made in writing this article.

perlengkapan bayi baru lahir United States |

6/28/2010 9:58:18 PM #

Hey very nice blog!! Man .. Beautiful .. Amazing .. I will bookmark your blog and take the feeds also...

nursing cover United States |

6/28/2010 9:58:19 PM #

I do not post on blogs, but I would like to say that this post really forced me to do so! really nice post.

bayi lucu United States |

6/28/2010 9:58:20 PM #

amazing stuff thanx

flu incubation period United States |

6/28/2010 9:58:21 PM #

Thank you for your information. Such a very fine post.

remedies sore throat United States |

6/28/2010 9:58:22 PM #

There is obviously a lot to know about this. I think you made some good points in Features also.

cost breast implants United States |

6/28/2010 9:58:23 PM #

I am very glad to see such information which I was searching for a long time.This made very glad..This site has given us an useful information..

surgery breast reduction United States |

6/28/2010 9:58:23 PM #

Thank you for the insight, i really appreciate your posts.

muscle weight gain United States |

6/28/2010 9:58:24 PM #

Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon.

girls party ideas United States |

6/28/2010 9:58:25 PM #

Thank you for your help!

women laptop bags United States |

6/28/2010 9:58:26 PM #

Your blog is so informative � keep up the good work!!!!

car brake parts United States |

6/28/2010 9:58:27 PM #

You are a very smart person!

continuing nursing education United States |

6/28/2010 9:58:28 PM #

Such a usefule blog�wow !!!!

protein whey powder United States |

6/28/2010 9:58:28 PM #

Interesting information. May I add this blog to my favorite ?

cost breast augmentation United States |

6/28/2010 9:58:29 PM #

I was wondering what is up with that weird gravatar??? I know 5am is early and I'm not looking my best at that hour, but I hope I don't look like this! I might however make that face if I'm asked to do 100 pushups. lol

parish vintage United States |

6/28/2010 9:58:30 PM #

upside is your future is in your hands. And the downside is your future is in your

ebooks download United States |

6/28/2010 9:58:31 PM #

Wonderful article, thanks for putting this together! This is obviously one great post. Thanks for the valuable information and insights you have so provided here

tv series download United States |

6/28/2010 9:58:32 PM #

Hello,I love reading through your blog, I wanted to leave a little comment to support you and wish you a good continuation. Wishing you the best of luck for all your blogging efforts.

manga free download United States |

6/28/2010 9:58:33 PM #

I keep listening to the news speak about getting free online grant applications so I have been looking around for the best site to get one.

make money online United States |

6/28/2010 9:58:34 PM #

What a great post. I have to say I really enjoyed reading it. Thanks!

health information United States |

6/28/2010 9:58:35 PM #

Your blog is so informative � keep up the good work!!!!

cell phone review United States |

6/28/2010 9:58:36 PM #

As a Newbie, I am always searching online for articles that can help me. Thank you

gendongan bayi United States |

Powered by BlogEngine.NET 1.5.0.7
Custom theme for digitalboon.com by Bron Skinner

About the author

A Software Developer with a keen artistic sense, I’ve spent the last couple years working with predominantly Microsoft-based technologies developing web applications. The majority of this time has been spent building applications with SilverlightTM that forward some rather unique approaches to interface design. I am currently working full time.

 

 

Make sure to check out The Forge.


Download Resume