Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

clickable world map 8

Status
Not open for further replies.

peterve

IS-IT--Management
Mar 19, 2000
1,348
NL
Hi all,

I want to include a world map in my VB.Net application.
The map needs to be clickable (based on countries) and I want to have the option to fill each country in a different country

Does anyone have an idea on how to do this ?

thanks

P

--------------------------------------------------------------------
--------------------------------------------------------------------
How can I believe in God when just last week I got my tongue caught in the roller of an electric typewriter?
---------------------------------------------------------------------
 
You might check out MSMapPoint. Is is similar to an office product, depending on what you need. Good Luck!

Have a great day!

j2consulting@yahoo.com
 
If you want to do this in your own form, here's an idea. It's slightly advanced, and there may be an easier way, but it would be the easiest way to maintain the map and click areas.

Make a copy of the map you want to use, using photoshop/gimp/paint make the "unclickable" areas black, then color each of the "clickable" areas different solid colors. This will take some time, but it's better then trying to set up 20,000 click points.

Next add your original map to the form. Trap the click event. Load your Color Coded map to an image object. Get the X,Y coordinates of the mouse click on the map and find the color of that pixel in the color coded map. Use the RBG value of that color to identify which country was clicked on.

-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
Rick

I do believe you dont need click points. Apparently it is possible to detect a click inside a polygon using some basic geometry. I started to look at this a while back but never finished it.

In other words it should be possible to define a polygon, and then detect a click inside of it.



Sweep
...if it works dont mess with it
 
Is this what you are wanting?


I created this using a scalar class that will scale the image to screen size and output an HTML file.

I also have a method that will work in ASPX but the mouse over menu needs adjustment. Let me know what you think.

Cassidy
 
Yup, perfect !

willing to share your code ?

--------------------------------------------------------------------
--------------------------------------------------------------------
How can I believe in God when just last week I got my tongue caught in the roller of an electric typewriter?
---------------------------------------------------------------------
 
Sure. I can share everything but the mouse over menu. Do you need the scaler functions and the map images?

Let me know.

Cassidy
 
Nice job CassidyHunt! I would be interested in whatever code you would be willing to share. Just send it to my signature. Thanks!

Have a great day!

j2consulting@yahoo.com
 
As mentioned before : I'm interested also :

peter.ve@telenet.be

--------------------------------------------------------------------
--------------------------------------------------------------------
How can I believe in God when just last week I got my tongue caught in the roller of an electric typewriter?
---------------------------------------------------------------------
 
Cool!

If you would share any code, I am interested: j_dimandja@hotmail.com

Thanks.
 
Here is the code. I will email you the image files and code so you can set it up. I have another draft of this in the works to be a control.

Lets start with the scaleimagemap.vb. This will take a set of image map coordinates, scale the image map to any size and return a new set of coordinates that coorlates to that scale. In addition it also replaces the link, hopefully the same in all the files, to a desired link. This is handy if you have a database you need to tie too.

Code:
Public Class scaleimagemap
    Inherits System.ComponentModel.Component

#Region " Component Designer generated code "

    Public Sub New(Container As System.ComponentModel.IContainer)
        MyClass.New()

        'Required for Windows.Forms Class Composition Designer support
        Container.Add(me)
    End Sub

    Public Sub New()
        MyBase.New()

        'This call is required by the Component Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Component overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Component Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Component Designer
    'It can be modified using the Component Designer.
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

#End Region
#Region " Remove Duplicate Map Coordinate Function "

    Public Function RemoveDuplicateMapCoordinates(ByVal sCoords As String)

        Dim sX(), sY(), sTemp, sTemp2 As String
        Dim iLen As Int32 = 1
        Dim iPos As Int32 = 1
        Dim i, iIndex As Int32

        Do Until iPos = 0
            iPos = InStr(iPos, sCoords, " ", CompareMethod.Text)
            If iPos <> 0 Then
                sCoords = Mid(sCoords, 1, (iPos - 1)) & Mid(sCoords, iPos + 1)
            End If
        Loop

        i = 1
        iIndex = 0
        iPos = 0
        iLen = 1

        For iLen = 1 To Len(sCoords)
            sTemp = Mid(sCoords, iLen, 1)
            If IsNumeric(sTemp) = True Then
                'Coordinate Number
                sTemp2 = sTemp2 & sTemp
            ElseIf sTemp = "," Then
                'Seperator

                If i = 1 Then
                    'X Value increment Arrays
                    iIndex += 1
                    ReDim Preserve sX(iIndex)
                    ReDim Preserve sY(iIndex)
                    sX(iIndex) = sTemp2
                    sTemp2 = ""
                    i = 2
                ElseIf i = 2 Then
                    'Y Value
                    sY(iIndex) = sTemp2
                    sTemp2 = ""
                    i = 1
                End If
            End If

        Next

        i = 1
        sTemp = ""
        sY(iIndex) = sTemp2
        For i = 1 To iIndex
            For t As Int32 = 1 To iIndex
                If i <> t Then
                    If sX(i) = sX(t) And sY(i) = sY(t) Then
                        'Found Duplicate
                        sX(i) = ""
                        sY(i) = ""
                    End If
                End If
            Next

            If sX(i) <> "" And sY(i) <> "" Then
                sTemp = sTemp & sX(i) & "," & sY(i) & " , "
            End If
        Next

        sTemp = Left(sTemp, (Len(sTemp) - 2))

        Return sTemp

    End Function
#End Region
#Region " Scale Image Map Function "
    Function ScaleImageMap(ByVal sCoords As String, ByVal dScale As Double)
        Dim sX(), sY(), sTemp, sTemp2 As String
        Dim iLen As Int32 = 1
        Dim iPos As Int32 = 1
        Dim i, iIndex As Int32

        Do Until iPos = 0
            iPos = InStr(iPos, sCoords, " ", CompareMethod.Text)
            If iPos <> 0 Then
                sCoords = Mid(sCoords, 1, (iPos - 1)) & Mid(sCoords, iPos + 1)
            End If
        Loop

        i = 1

        For iLen = 1 To Len(sCoords)
            sTemp = Mid(sCoords, iLen, 1)
            If IsNumeric(sTemp) = True Then
                'Coordinate Number
                sTemp2 = sTemp2 & sTemp
            ElseIf sTemp = "," Then
                'Seperator

                If i = 1 Then
                    'X Value increment Arrays
                    iIndex += 1
                    ReDim Preserve sX(iIndex)
                    ReDim Preserve sY(iIndex)
                    sX(iIndex) = sTemp2
                    sTemp2 = ""
                    i = 2
                ElseIf i = 2 Then
                    'Y Value
                    sY(iIndex) = sTemp2
                    sTemp2 = ""
                    i = 1
                End If
            End If
        Next

        sY(iIndex) = sTemp2
        i = 1

        If dScale > 0 Then
            For i = 1 To iIndex
                sX(i) = Int(CInt(sX(i)) * dScale)
                sY(i) = Int(CInt(sY(i)) * dScale)
            Next
        End If

        sTemp = ""

        For i = 1 To iIndex
            sTemp = sTemp & sX(i) & "," & sY(i) & ","
        Next

        sTemp = Left(sTemp, (Len(sTemp) - 1))

        sTemp = RemoveDuplicateMapCoordinates(sTemp)

        Return sTemp
    End Function
#End Region
#Region " Find All Area Tags and Coordinates "
    Public Function FindAreaTags(ByVal sHTML As String, Optional ByVal sURL As String = "default.aspx", Optional ByVal bScale As Boolean = False, Optional ByVal dScale As Double = 1, Optional ByVal sMouseOver As String = "nothing")
        Dim iPos, iPos2, iLen As Int32
        Dim sTemp, sBegin, sEnd, sTemp2 As String

        iPos = InStr(1, sHTML, "<AREA", CompareMethod.Text)
        iPos2 = InStr(iPos, sHTML, "COORDS=", CompareMethod.Text) + 7
        iPos2 = iPos2 - iPos
        sBegin = Mid(sHTML, iPos, iPos2) & "'"
        sEnd = "'" & sMouseOver & " HREF='" & sURL & "'>"

        iPos2 = 1
        iPos = 1

        Do Until iPos = 0
            iPos = InStr(iPos2, sHTML, "COORDS=" & Chr(34), CompareMethod.Text)
            If iPos <> 0 Then
                iPos2 = InStr(iPos, sHTML, "HREF", CompareMethod.Text)
                iPos2 = (iPos2 - 10) - iPos
                iPos = iPos + 8
                If bScale = True Then
                    'Need to scale coordinates
                    sTemp2 = ScaleImageMap(Mid(sHTML, iPos, iPos2), dScale)
                Else
                    sTemp2 = Mid(sHTML, iPos, iPos2)
                End If
                sTemp = sTemp & sBegin & sTemp2 & sEnd & vbCrLf
                iPos2 = (iPos + iPos2) + 10
            End If
        Loop



        Return sTemp
    End Function
#End Region
End Class

Next I use a function that will extract the image map coordinates out of all the image map files in a directory.

Code:
 Public Function BuildImageMap(Optional ByVal bScale As Boolean = False, Optional ByVal dScale As Double = 1) As String
        Dim oDirectory As New IO.DirectoryInfo("c:\program files\mapnet\2\maps")
        Dim oFiles() As IO.FileInfo = oDirectory.GetFiles
        Dim oFileinfo As IO.FileInfo
        Dim oFile As IO.File
        Dim sRead As String
        Dim oImageMap As New scaleimagemap
        Dim sHTML, sMouseOver As String

        For Each oFileinfo In oFiles
            sRead = oFile.OpenText(oFileinfo.FullName).ReadToEnd

            sMouseOver = " onMouseOver=" & Chr(34) & "popup('" & Strings.Left(oFileinfo.Name, (Len(oFileinfo.Name)) - 5) & "',1)" & Chr(34) & " onMouseOut=" & Chr(34) & "popdown()" & Chr(34)
            sHTML = sHTML & oImageMap.FindAreaTags(sRead, "country.asp?c=" & Strings.Left(oFileinfo.Name, (Len(oFileinfo.Name) - 5)), bScale, dScale, sMouseOver)
        Next

        sHTML = "<IMG SRC='World.gif' WIDTH=" & Int(cWidth * dScale) & " HEIGHT=" & Int(cHeight * dScale) & " BORDER=0 ALT='' USEMAP='#World_Map'><MAP NAME='World_Map'>" & sHTML & "</MAP>"

        Return sHTML

    End Function

I haven't had a chance to clean this up so that it is handled in the scaleimagemap.vb but it does the trick and it allows you to add items such as menu's. I handle my menu by using a managedHTML.vb file that outputs all the javascript needed to construct the menu's. Unfortunatly I go a bit lazy and bought a menu component and customized it to my needs. So I can't share that with you.

The final bit of information is retrieving the values for screen resolution. In this draft I made a simple default.html file that used Javascript to modify the URL and send me the correct screen size to scale the image and maps.

Code:
<html>

<body onload="storeWidthAndHeightToTheServer()">

<form id="resolution" method="post" action="webform1.aspx">

</form>

<script language="javascript">

function storeWidthAndHeightToTheServer()

{ 

with (document.getElementById('resolution'))

{

var InitStr;

InitStr = "webform1.aspx?ScreenWidth=";

InitStr += screen.width;

InitStr += "&ScreenHeight=";

InitStr += screen.height;

action = InitStr;

submit();

}

}

</script>

</body>

</html>

After you do everything above to tie it all together you just need to call the functions from your page load event.

Code:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
        'Constant Size of map width = 2438 height = 1705
        Session("ScreenWidth") = (HttpContext.Current.Request.QueryString("ScreenWidth"))
        Session("ScreenHeight") = (HttpContext.Current.Request.QueryString("ScreenHeight"))
        If Session("ScreenWidth") = "" Then
            Response.Redirect("default.htm")
        Else
            If Not IsPostBack Then
                Dim dWidth, dHeight, dScale As Double

                dWidth = CDbl(Session("ScreenWidth")) / cWidth
                dHeight = CDbl(Session("ScreenHeight")) / cHeight

                If dWidth < dHeight Then
                    dScale = dWidth - 0.1
                Else
                    dScale = dHeight - 0.1
                End If
                BuildImageMap(True, dScale)
            End If
        End If

    End Sub

The hard part of the whole thing is building the individual image maps.

Hopefully this helps.

I will contact people who are interested in the files directly.

Cassidy
 
I do believe you dont need click points. Apparently it is possible to detect a click inside a polygon using some basic geometry. I started to look at this a while back but never finished it.

In other words it should be possible to define a polygon, and then detect a click inside of it.

The world has 192 countries, if you want to break them down further by states, that number jumps quickly. Me personally, I would not like to have to set up 192 different polygons to roughly cover each country when I could take a map like the one in the above link, spend less than an hour in photoshop, and wind up with a perfect clickable map. How long would it take to set up and align 192 polygons averaging 6 sides?

-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
I set up all the image maps in photoshop and image ready. took about three days. I went for the really detailed resolution instead of 6 sided polygon. That is why I had to create the scaler function. Something that made it a bit easier is I had an illustrator file with the polygons on sepearate layers for each country and state.

Cassidy
 
took about three days

Yeah... not my idea of fun. If I get a chance I'll throw together a click mask, it sounds like a fun lunch project.

-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
If I get a chance I'll throw together a click mask, it sounds like a fun lunch project.
Rick..take a break, and savour those sandwiches.



Sweep
...if it works dont mess with it
 
NO, let him work and then copy his code here.

Thank you Rick.

Not that I will ever use this.

Christiaan Baes
Belgium

If you want to get an answer read this FAQ faq796-2540
There's no such thing as a winnable war - Sting
 
Actually Chrissie, Imagine having a completly skinnable app with no buttons. Stick an image on a form, have a matching click mask to go with it, all you need is a handle for the click even on the image and a data or hash table with the color/event lookup. I think it could have use even beyond a map.

Now if I could get this damn sales leads report to print I'd work on it. Stupid crystal reports! gerah!

-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
I am all for options. My end goal for this was to use GDI to draw a picture dynamically, make it clickable, tie it to a database, and have it compiled as a control that I only have to set properties on. World map piece of it just happen to be a side project for management to do their marketing.

 
Hrm, so much for doing it today. I have a Ecommerce class tonight, maybe I can play with it then .

-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
Got it! Spent about an hour and a half including code and writing the XML generation. I figured anyone with dataset -> XML questions might find it helpful.

Anyways, I used this US Map image: (Cropped from Cassidy's image)
USA.bmp


Then I used Photoshop to make this:
USAClickMap.bmp

If you look closely, you can see the slight blue shift in colors from west to east.

Big whopping code: (Excerpt, download the zip for the full code and build)
Code:
    Private Sub pbMap_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pbMap.MouseDown
        Dim ClickIndex As Integer
        Dim dr() As DataRow

        'Get the blue value of the pixel from the Click Map
        'image at the location clicked on the Map. If you
        'have more then 256 values, you'll want to use
        'a simple algorythm to get the RGB value
        ClickIndex = imgClickMap.GetPixel(e.X, e.Y).B

        'Grab the row from the datatable that has the color index clicked
        dr = dsStates.Tables("States").Select("Index=" & ClickIndex)
        If dr.Length > 0 Then
            lblState.Text = dr(0).Item("Name").ToString
        Else
            lblState.Text = ""
        End If
    End Sub

Code:
-Rick

----------------------
[banghead]If you're about to post an ASP.Net question,
please don't do it in the VB.Net forum[banghead]

[monkey] I believe in killer coding ninja monkeys.[monkey]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top