我想製作一個顯示每個狀態的地圖,當將鼠標懸停在某個狀態上時,相應的形狀會改變顏色並且會顯示一些關於它的信息。爲按鈕創建自定義形狀
下面是類似的東西 kartograph.org/showcase/usa-projection
使用.NET 4.5,C#基於Web的例子,和WinForms是否有可能與巴頓和處理鼠標事件的實現這一目標?
我想製作一個顯示每個狀態的地圖,當將鼠標懸停在某個狀態上時,相應的形狀會改變顏色並且會顯示一些關於它的信息。爲按鈕創建自定義形狀
下面是類似的東西 kartograph.org/showcase/usa-projection
使用.NET 4.5,C#基於Web的例子,和WinForms是否有可能與巴頓和處理鼠標事件的實現這一目標?
這不是一個完整的答案,但可能會讓你走上正確的道路。
WinForms不會讓你以這種方式使用Button
對象; WinForms按鈕的定製能力非常有限 - 如果它是一個選項,WPF可能會適用於此。
要在WinForms中執行此操作,您可能需要使用GDI並將每個狀態加載到它自己的Graphics對象中,併爲Click事件等編寫自己的管道。雖然我不能提供一個具體的例子,但它應該是可行的,但它也可能是一個相當大的工作量(特別是對於諸如圖像的透明部分之類的東西)。但是,如果您要麼查看WPF,要麼查看與GDI對象的交互,您應該可以取得進展。
我並不想要一個特別的按鈕,但一些工作..我想我會採取你的建議和使用WPF,但我必須先熟悉它自己..感謝您的幫助 – 2015-02-06 20:37:11
這個答案完全忽略了關於創建具有滑稽形狀的按鈕的問題,而只處理了構建類似於您顯示的鏈接的示例:通過單擊或懸停鼠標來標識地圖上的狀態。
要識別的狀態很簡單:
如果你可以指定每個狀態的顏色(即使它僅僅是非常略有不同),你可以使用GetPixel
來檢查哪個國家/彩色鼠標點擊或爲懸停..
如果您不想看到可見的顏色,您仍然可以使用相同的技巧,只需使用兩個疊加的地圖並顯示頂部地圖,同時使用下面的彩色地圖作爲查找表。
當然,你甚至不需要把查找映射到控件中;只要它與可見地圖尺寸相同,就可以簡單地使用它的Bitmap
。
在winforms中不會佔用更多的代碼行。設置狀態列表並填充顏色將會有更多的工作。
改變顏色比較棘手。我想我會在這裏使用一個相當不同的方法:編碼floodfill算法非常簡單; wikipedia有幾個很好的,特別是沒有遞歸(基於隊列)的實現非常簡單。
所以,你可以使用地圖的覆蓋副本,floodfill狀態鼠標懸停在..(對於這個工作,你需要確保狀態可以被floodfilled,即他們有封閉輪廓,這可能是他們着色的準備工作的一部分。)
當鼠標移動到不同的國家/顏色,你會恢復原來的地圖..
你舉的例子有一個很好的,如果有點慢,動畫。這將更加棘手。如果你需要,也許WPF
真的是值得考慮的。雖然着色動畫Winforms
是可行的爲好,也許有Color Matrix
和Timer
它肯定不是爲浮華建..
這裏是一塊代碼去至少有一半的方式:
// simple but effective floodfill
void Fill4(Bitmap bmp, Point pt, Color c0, Color c1)
{
Rectangle bmpRect = new Rectangle(Point.Empty, bmp.Size);
Stack<Point> stack = new Stack<Point>();
int x0 = pt.X;
int y0 = pt.Y;
stack.Push(new Point(x0, y0));
while (stack.Any())
{
Point p = stack.Pop();
if (!bmpRect.Contains(p)) continue;
Color cx = bmp.GetPixel(p.X, p.Y);
if (cx == Color.Black) return;
if (cx == SeaColor) return;
if (cx == c0)
{
bmp.SetPixel(p.X, p.Y, c1);
stack.Push(new Point(p.X, p.Y + 1));
stack.Push(new Point(p.X, p.Y - 1));
stack.Push(new Point(p.X + 1, p.Y));
stack.Push(new Point(p.X - 1, p.Y));
}
}
}
// create a random color for the test
Random R = new Random();
// current and last mouse location
Point mouseLoc = Point.Empty;
Point lastMouseLoc = Point.Empty;
// recognize that we have move inside the same state
Color lastColor = Color.White;
// recognize the outside parts of the map
Color SeaColor = Color.Aquamarine;
// start a timer since Hover works only once
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
mouseLoc = e.Location;
timer1.Stop();
timer1.Interval = 333;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
// I keep the map in the Background image
Bitmap bmp = (Bitmap)pictureBox1.BackgroundImage;
// have we left the image?
if (!new Rectangle(Point.Empty, bmp.Size).Contains(mouseLoc)) return;
// still in the same state: nothing to do
if (lastColor == bmp.GetPixel(mouseLoc.X, mouseLoc.Y)) return;
// a random color
Color nextColor = Color.FromArgb(255, R.Next(255), R.Next(255), R.Next(256));
// we've been in the map before, so we restore the last state to white
if (lastMouseLoc != Point.Empty)
Fill4(bmp, lastMouseLoc,
bmp.GetPixel(lastMouseLoc.X, lastMouseLoc.Y), Color.White);
// now we color the current state
Fill4(bmp, mouseLoc, bmp.GetPixel(mouseLoc.X, mouseLoc.Y), nextColor);
// remember things, show image and stop the timer
lastMouseLoc = mouseLoc;
lastColor = nextColor;
pictureBox1.Image = bmp;
timer1.Stop();
}
所有你需要運行它是一個PictureBox pictureBox1
和Timer timer1
,並且只有3種顏色地圖的版本:黑色,白色和海藍寶石。
它會做的是畫一個隨機顏色懸停的狀態。
您的下一步是創建一個包含數字,標題和信息文本的所有狀態列表。然後,您創建第二個版本的地圖,使用從州編號中派生出的顏色爲每個州的顏色着色。
如果稍微擴大一點,可以使用上面的代碼着色。
最後你的代碼在Tick
事件的查找來獲得信息,以在Tooltip
顯示..
當然,這是假設你是滿意與地圖爲Bitmap
工作。要鏈接的源使用SVG
文件,其中所有數據都以XML
格式存儲爲矢量數據。解析這個得到Points
爲GraphicsPath
也是一個選項,然後將在矢量領域工作。但我想這可能需要幾天的時間才能建立..
我完成,粗糙的版本,包括創建顏色映射的代碼和執行查找的代碼進來ca. 150行,沒有評論。
你在用什麼?的WinForms? WPF? – Omada 2015-02-06 19:51:29
歡迎來到StackOverflow,很難根據你的問題提供答案。你究竟想達到什麼目的?你使用WPF,WinForms,網頁嗎?什麼框架版本 - 你嘗試過什麼? – STW 2015-02-06 19:52:05
在什麼情況下的按鈕?一個WPF或Windows商店應用程序?使用混合來追蹤一個PNG的形狀。 – OakNinja 2015-02-06 19:52:41