The good news first: The programming part is not so hard and even with good old Winforms you can do the core checks in a few lines. The clickable areas can't be Buttons in Winforms, however.
Here are two solutions:
Solution 1 : You can define a list of areas, called regions and test if one got clicked.
Here is a start: I define a very simple Rectangle Region
and a not so simple Polygon Region
and test on each click if one was hit. If it was hit I output its data into the Form's title text:
//..
using System.Drawing.Drawing2D;
//..
public Form1()
{
InitializeComponent();
// most real states don't look like rectangles
Region r = new Region(new Rectangle(0, 0, 99, 99));
regions.Add(r);
List<int> coords = new List<int>() {23,137, 76,151, 61,203,
117,283, 115,289, 124,303, 112,329, 76,325, 34,279, 11,162};
List<Point> points = new List<Point>();
for (int i = 0; i < coords.Count ; i += 2)
points.Add(new Point(coords[i], coords[i+1]));
byte[] fillmodes = new byte[points.Count];
for (int i = 0 ; i < fillmodes.Length; i++) fillmodes[i] = 1;
GraphicsPath GP = new GraphicsPath(points.ToArray(), fillmodes);
regions.Add(r);
}
List<Region> regions = new List<Region>();
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
using (Graphics G = pictureBox1.CreateGraphics() )
foreach(Region r in regions)
{
Region ri = r.Clone();
ri.Intersect(new Rectangle(e.X, e.Y, 1, 1));
if (!ri.IsEmpty(G)) // hurray, we got a hit
{ this.Text = r.GetBounds(G).ToString(); break; }
}
}
The regions in the test programm are not visible. For testing you may want to add something like this:
private void button1_Click(object sender, EventArgs e)
{ // paint a non-persistent filling
using (Graphics G = pictureBox1.CreateGraphics())
foreach (Region r in regions)
{ G.FillRegion(Brushes.Red, r); }
}
But now for the bad news: You can define regions to be complicated polygons that look like real states, however that is a lot of work! There are ready-made image map editors out there in the web for making clickable maps on websites. Your best course might be to use one of these to create all those polygons and then convert the html output to a list of points you can read into your program. You may even get lucky and find ready image maps for the USA, but I haven't looked..
Update: There are many image maps of the USA out there. One is even on wikipedia. Converting these coordinates to fit your map will be a task but lot easier than creating them from scratch, imo. I have changed the code to include one list of cordinates from the wikipedia source. Guess the state!
I have implmented a program that lets you click on a state and displays the name in 78 lines of code, excluding the text file with the 50 states.
Solution 2:
Instead of a list of polygons you can prepare a colored map and use the colors as keys into a Dictionary<Color, string>
or Dictionary<Color, StateInfo>
. You must make sure that each state has one unique color and that the image is not compressed as jpeg, which would introduce artifacts and mess up the key mapping.
Next you map each color to the related info; this is the real work because you must know those states to create the Dictionary ;-)
Finally you can look up the clicked color in the Dictionary you have created:
Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];
If you are using a class or struct as your value in the dictionary you can include the capital etc..
You can zoom but must scale the click location accordingly; you can even display a geographical Image if you look up the key color not in the PictureBox but in an invisible color code bitmap.
All in all an even simpler solution imo.. your pick!
Once you got that working, you can play with drag&drop. Here you'll want to test on DragDrop or maybe on Mouseup to see where you have dropped the Label.
This is a nice project and well worth of creating a few classes to make things easier and more expandable..!
For real Buttons you may get lucky with WPF.