Trying to find how to make an imagemap style Deep Zoom collection in a similar way to the way the Hard Rock Memorabillia site does and came across
this post by Jim Lynn. It explains how to go about making a hit detector by explaining all the head messing stuff surrounding pixel sizes, viewport origins and widths and so on. Coupled with some talking to javascript, we have a means of calling javascript functions when a particular DZ sub image is in a particular part of the viewport. Yay!
Make sure your Silverlight object has an onLoaded handler associated with it, so:
<param value="OnSilverlightLoaded" name="onload">or set the OnLoad attribute in the asp:silverlight tag if using the .aspx route
Then add the following javascript functions:
function OnSilverlightLoaded(sender, args)
{
document.getElementById("sl1").Content.EntryPoint.CallbackToBrowser = onManagedCallback;
// where sl1 is the clientID of the Silverlight Control
// You _should_ be able to use sender but I couldn't get this to work and I had to go feed the baby!
}
// Our callback handler
function onManagedCallback(sender, args)
{
// Basically, do whatever. The _stuff_ is in args.Data
var target = document.getElementById("eventDiv");
eventDiv.innerHTML = args.Data;
}
In your Page.xaml.cs
[ScriptableMember()]
public event EventHandler CallbackToBrowser;
public class EventArgs : EventArgs
{
private T _data;
public EventArgs(T args)
{
_data = args;
}
[ScriptableMember()]
public T Data
{
get
{
return _data;
}
}
}
private void DetectCollision()
{
if (CallbackToBrowser != null)
{
int imageIndex = -1;
Point viewportCenter = new Point();
viewportCenter.X = msi.ViewportOrigin.X + (msi.Width/ 2);
viewportCenter.Y = msi.ViewportOrigin.Y + (msi.Height / 2);
if (HitTest(msi, viewportCenter, ref imageIndex))
{
CallbackToBrowser(this, new EventArgs("We hit: " + imageIndex.ToString()));
}
else
{
CallbackToBrowser(this, new EventArgs("No image"));
}
}
}
/// Given an element point relative to the DeepZoom image
/// return whether the point hits any subimages in the collection
/// parentImage: Parent image whose subimages we want
/// to test
/// p: Point to test (in element coordinate space)
/// imageindex: index into the SubImages collection
/// returns: true if a hit was found
/// http://jimlynn.blogspot.com/2008/04/silverlight-deep-zoom-collections-and.html
private bool HitTest(MultiScaleImage parentImage, Point p, ref int imageindex)
{
bool gotHit = false;
for (int i = 0; i < parentImage.SubImages.Count; i++)
{
MultiScaleSubImage image = parentImage.SubImages[i];
// Start with the logical origin of the image
Point topLeft = image.ViewportOrigin;
// Relative to the parent image, this coordinate is
// scaled by ViewportWidth (and the coords are negative)
topLeft.X = -(topLeft.X / image.ViewportWidth);
topLeft.Y = -(topLeft.Y / image.ViewportWidth);
// Calculate the logical width relative to the parent
double width = 1 / image.ViewportWidth;
// And get the height from the aspect ratio
double height = width / image.AspectRatio;
// Create a point representing the bottom left logical point
Point bottomright = new Point(topLeft.X + width, topLeft.Y + height);
// Now we've got the topleft and bottom right points
// in coordinates relative to the parent MultiScaleImage
// We can now use LogicalToElement to convert to Silverlight
// coordinates
topLeft = parentImage.LogicalToElementPoint(topLeft);
bottomright = parentImage.LogicalToElementPoint(bottomright);
// Now do the hit test
Rect r = new Rect(topLeft, bottomright);
if (r.Contains(p))
{
gotHit = true;
imageindex = i;
image.Opacity = 1;
}
else
{
image.Opacity = 0.8;
}
}
return gotHit;
}
and then call
DetectCollision();
in the appropriate handlers. If you edit the Page.xaml.cs generated by Deep Zoom Composer then it will contain a block of code containing the appropriate handlers for zooming and dragging written by Messrs Lutz Gerhard, Peter Blois, and Scott Hanselman.
I added it to the MouseLeftButtonUp handler, MouseMove handler and Zoom method