Common Custom JavaScript
Common_CustomJavaScript_VBNet\MapDataGridHover.aspx.vb
' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 

Imports Microsoft.VisualBasic
Imports System
Public Partial Class MapDataGridHover
  Inherits System.Web.UI.Page
  #Region "ASP.NET Page Life Cycle Event Handlers"

  Protected Sub Page_Load(ByVal sender As Object, ByVal eventArgs As System.EventArgs)
    ' Get the __EVENTTARGET request parameter.  This will specify any controls that are
    ' the target of the event that triggered the Page request (i.e. postback)
    Dim requestParameters As System.Collections.Specialized.NameValueCollection = Page.Request.Params
    Dim controlEvent As String = Nothing
    Dim controlID As String = requestParameters("__EVENTTARGET")

    ' Check whether the __EVENTTARGET parameter is null or empty and whether it contains the
    ' GridView control's ID
    If (Not String.IsNullOrEmpty(controlID)) AndAlso controlID.Contains(GridView1.ID) Then
      ' Get any event arguments from the Page request
      controlEvent = requestParameters("__EVENTARGUMENT")
      ' If the event arguments contain the string indicating initiation of our
      ' custom postback event, call the method to zoom to the feature corresponding
      ' to the clicked row
      If controlEvent.Contains("CustomSelect$") Then
        SelectRow(controlEvent, "EventID")
      End If
    End If

    ' Make sure the page is not loading as a result of a postback (i.e. is in initial page load)
    If (Not IsPostBack) Then
      ' Create table to hold data to link to graphics
      Dim dataTable As System.Data.DataTable = New System.Data.DataTable("FireEvents")

      ' Create and add columns
      Dim eventIDDataColumn As System.Data.DataColumn = New System.Data.DataColumn("EventID")
      Dim eventInfoDataColumn As System.Data.DataColumn = New System.Data.DataColumn("EventInfo")
      dataTable.Columns.Add(eventIDDataColumn)
      dataTable.Columns.Add(eventInfoDataColumn)

      ' Create, populate, and add three rows
      Dim eventDataRow As System.Data.DataRow = dataTable.NewRow()
      eventDataRow(eventIDDataColumn) = 1
      eventDataRow(eventInfoDataColumn) = "value1"
      dataTable.Rows.Add(eventDataRow)

      eventDataRow = dataTable.NewRow()
      eventDataRow(eventIDDataColumn) = 2
      eventDataRow(eventInfoDataColumn) = "value2"
      dataTable.Rows.Add(eventDataRow)

      eventDataRow = dataTable.NewRow()
      eventDataRow(eventIDDataColumn) = 3
      eventDataRow(eventInfoDataColumn) = "value3"
      dataTable.Rows.Add(eventDataRow)

      ' Create a dataset and add the table to it
      Dim dataSet As System.Data.DataSet = New System.Data.DataSet()
      dataSet.DataSetName = "FireEventsDataSet"
      dataSet.Tables.Add(dataTable)

      ' Set the dataset as the GridView's data source and add a handler for the GridView's RowDataBound event
      GridView1.DataSource = dataSet
      AddHandler GridView1.RowDataBound, AddressOf GridView1_RowDataBound

      ' Add graphics to the map
      DrawGraphics(dataTable)

      ' Bind the GridView to its data source and adjust its appearance
      GridView1.DataBind()
      GridView1.Visible = True
      GridView1.BorderWidth = 10
    End If
  End Sub

  #End Region

  #Region "WebControl Event Handlers"

  Private Sub GridView1_RowDataBound(ByVal sender As Object, ByVal gridViewRowEventArgs As System.Web.UI.WebControls.GridViewRowEventArgs)
    ' Only manipulate data rows
    If gridViewRowEventArgs.Row.RowType = System.Web.UI.WebControls.DataControlRowType.DataRow Then
      Dim graphicsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality = CType(Map1.GetFunctionality("ADFGraphicsResource"), ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)

      Dim graphicsTableName As String = TryCast(Session("graphicsTableName"), String)
      If graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(graphicsTableName) Then
        Dim datasetName As String = graphicsMapFunctionality.GraphicsDataSet.DataSetName

        Dim graphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer = TryCast(graphicsMapFunctionality.GraphicsDataSet.Tables(graphicsTableName), ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer)
        Dim graphicsLayerClientID As String = Map1.GetGraphicsLayerClientID(graphicsLayer)
          'string.Format("{0}_{1}", datasetName, graphicsTableName);

        Dim gridViewRow As System.Web.UI.WebControls.GridViewRow = gridViewRowEventArgs.Row

        ' The index of the graphic feature is needed to get a reference to the graphic feature client-side.
        ' The index of a graphic feature is zero-based, and is determined by the order in which it was added
        ' to its graphic feature group.  Here, we can use the gridViewRow's RowIndex, because we know that 
        ' the graphic features were added to the graphics layer in the order of the rows of the data table 
        ' that is bound to the GridView control
        Dim graphicFeatureIndex As Integer = gridViewRow.RowIndex

        ' Create a JavaScript string that will (1) set the background color of the current
        ' row, (2) get the graphicFeatureGroup (i.e. layer) for the GraphicsLayer, (3) get
        ' the graphicFeature corresponding to the current row index from the 
        ' graphicFeatureGroup, and (4) set the highlight on the graphicFeature
        Dim jsSetRowAndFeatureHighlight As String = "this.style.backgroundColor='{0}';" & "var graphicFeatureGroup = $find('{1}'); " & "var graphicFeature = graphicFeatureGroup.get({2}); " & "graphicFeature.set_highlight({3});"

        ' Assign the JavaScript string to the current row's onmouseover event.  Specify the
        ' row's background color as gray and the parameter to graphicFeature.set_highlight
        ' as true
        gridViewRow.Attributes.Add("onmouseover", String.Format(jsSetRowAndFeatureHighlight, "gray", graphicsLayerClientID, graphicFeatureIndex, "true"))

        ' Assign the JavaScript string to the current row's onmouseout event.  Specify the
        ' row's background color as white and the parameter to graphicFeature.set_highlight
        ' as false
        gridViewRow.Attributes.Add("onmouseout", String.Format(jsSetRowAndFeatureHighlight, "white", graphicsLayerClientID, graphicFeatureIndex, "false"))

        ' Construct a JavaScript string that uses Web ADF JavaScript to (1) retrieve the
        ' graphicFeatureGroup (i.e. layer) corresponding to the graphics data layer, (2)
        ' get the graphicFeature corresponding to the current row, (3) get the geometry of
        ' the graphicFeature, (4) get the Page's client-side map object, and (5) zoom to 
        ' the graphicFeature
        Dim jsZoomToFeature As String = String.Format("var graphicFeatureGroup = $find('{0}'); " & "var graphicFeature = graphicFeatureGroup.get({1}); " & "var geometry = graphicFeature.get_geometry();" & "var map = $find('{2}');" & "map.zoomTo(geometry, .025, true);", graphicsLayerClientID, graphicFeatureIndex, Map1.ClientID)

        ' Handle click on client
        gridViewRow.Attributes.Add("onclick", jsZoomToFeature)

        ' Handle click on server
        'string jsDoPostback = ClientScript.GetPostBackEventReference(gridViewRow, "CustomSelect$" +
        '    gridViewRow.RowIndex);
        'gridViewRow.Attributes.Add("onclick", jsDoPostback);
      End If
    End If
  End Sub

  #End Region

  #Region "Instance Methods"

  Private Sub DrawGraphics(ByVal dataTable As System.Data.DataTable)
    ' Get the map functionality for the graphics resource
    Dim graphicsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality = CType(Map1.GetFunctionality("ADFGraphicsResource"), ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)

    ' Make sure the graphics have not already been added to the map
    If (Not Session("graphicsTableName") Is Nothing) OrElse (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(CStr(Session("graphicsTableName")))) Then
      Return
    End If

    ' Initialize default symbol
    Dim defaultSymbol As ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol = New ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/red_fire.gif")
    defaultSymbol.XOffset = 16
    defaultSymbol.YOffset = 16
    defaultSymbol.Height = 32
    defaultSymbol.Width = 32
    defaultSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF

    ' Create default renderer with default symbol
    Dim defaultRenderer As ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer = New ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(defaultSymbol)

    ' Initialize selected symbol
    Dim selectedSymbol As ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol = New ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/yellow_fire.gif")
    selectedSymbol.XOffset = 16
    selectedSymbol.YOffset = 16
    selectedSymbol.Height = 32
    selectedSymbol.Width = 32
    selectedSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF

    ' Create selected renderer with selected symbol
    Dim selectedRenderer As ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer = New ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(selectedSymbol)

    ' Initialize highlight symbol
    Dim highlightSymbol As ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol = New ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/blue_fire.gif")
    highlightSymbol.XOffset = 16
    highlightSymbol.YOffset = 16
    highlightSymbol.Height = 32
    highlightSymbol.Width = 32
    highlightSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF

    ' Create highlight renderer with highlight symbol
    Dim highlightRenderer As ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer = New ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(highlightSymbol)

    ' Add a geometry column to the events table
    dataTable.Columns.Add("ADFGeometry", GetType(ESRI.ArcGIS.ADF.Web.Geometry.Geometry))

    ' Convert the table to a feature graphics layer
    Dim eventsFeatureGraphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer = TryCast(ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(dataTable, defaultRenderer, selectedRenderer, highlightRenderer, False), ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer)

    ' Assign the layer's name and store it in session
    eventsFeatureGraphicsLayer.TableName = "MyEvents"
    Session("graphicsTableName") = eventsFeatureGraphicsLayer.TableName

    ' Create a random point geometry for each row in the table underlying the grapics layer
    Dim randomClass As System.Random = New System.Random()
    For Each dataRow As System.Data.DataRow In eventsFeatureGraphicsLayer.Rows
      Dim x As Integer = randomClass.Next(-120, -80)
      Dim y As Integer = randomClass.Next(25, 45)
      Dim adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point = New ESRI.ArcGIS.ADF.Web.Geometry.Point(x, y)
      adfPoint.SpatialReference = Map1.SpatialReference
      dataRow(eventsFeatureGraphicsLayer.GeometryColumnName) = adfPoint
    Next dataRow

    ' Render the graphics layer on the client without callouts (i.e. maptips)
    eventsFeatureGraphicsLayer.RenderOnClient = True
    eventsFeatureGraphicsLayer.EnableCallout = False

    ' Add the graphics layer to the graphics resource
    graphicsMapFunctionality.GraphicsDataSet.Tables.Add(eventsFeatureGraphicsLayer)

    ' Refresh the graphics resource so the new graphics layer appears
    Map1.RefreshResource(graphicsMapFunctionality.Name)
  End Sub

  Private Sub SelectRow(ByVal controlEvent As String, ByVal uniqueIDFieldName As String)
    ' Parse the control event string
    Dim controlEventArray As String() = controlEvent.Split("$"c)
    ' Set the selected index of the GridView to the argument of the control event
    GridView1.SelectedIndex = System.Int32.Parse(controlEventArray(1))
    ' Set the text color of the selected row to red
    GridView1.SelectedRowStyle.ForeColor = System.Drawing.Color.Red

    ' Find the column index of the unique ID field
    Dim uniqueIDFieldIndex As Integer = 0
    For Each dataControlField As System.Web.UI.WebControls.DataControlField In GridView1.Columns
      If dataControlField.HeaderText = uniqueIDFieldName Then
        Exit For
      End If

      uniqueIDFieldIndex += 1
    Next dataControlField

    ' Get the value of the unique ID field from the selected row
    Dim selectedID As String = GridView1.SelectedRow.Cells(uniqueIDFieldIndex).Text

    ' Get the map functionality for the graphics resource
    Dim graphicsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality = CType(Map1.GetFunctionality("ADFGraphicsResource"), ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)

    ' Make sure the target graphics layer is present in the graphics resource
    Dim graphicsTableName As String = TryCast(Session("graphicsTableName"), String)
    If graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(graphicsTableName) Then
      ' Get the target graphics layer
      Dim graphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer = TryCast(graphicsMapFunctionality.GraphicsDataSet.Tables(graphicsTableName), ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer)

      ' Unselect all features in the graphics layer
      For Each dataRow As System.Data.DataRow In graphicsLayer.Rows
        dataRow("IS_SELECTED") = False
      Next dataRow

      ' Use the event ID of the selected row in the GridView to retrieve the corresponding row in the data table
      ' underlying the linked graphics layer
      Dim dataRowArray As System.Data.DataRow() = graphicsLayer.Select(String.Format("EventID = '{0}'", selectedID))

      ' Assume that only one row was returned from the select operation, making the first row in the array
      ' the one that corresponds to the graphic we wish to select
      Dim selectedDataRow As System.Data.DataRow = dataRowArray(0)
      selectedDataRow("IS_SELECTED") = True

      ' Get the selected row's geometry
      Dim adfGeometry As ESRI.ArcGIS.ADF.Web.Geometry.Geometry = graphicsLayer.GeometryFromRow(selectedDataRow)

      ' Get the envelope of the geoemtry
      Dim boundingEnvelope As ESRI.ArcGIS.ADF.Web.Geometry.Envelope = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope(Double.MaxValue, Double.MaxValue, Double.MinValue, Double.MinValue)

      If TypeOf adfGeometry Is ESRI.ArcGIS.ADF.Web.Geometry.Polygon Then
        BoundingExtent(CType(adfGeometry, ESRI.ArcGIS.ADF.Web.Geometry.Polygon), boundingEnvelope)
        ' Expand the envelope to include some area around the feature on the map
        boundingEnvelope.Expand(5)
      ElseIf TypeOf adfGeometry Is ESRI.ArcGIS.ADF.Web.Geometry.Point Then
        BoundingExtent(CType(adfGeometry, ESRI.ArcGIS.ADF.Web.Geometry.Point), boundingEnvelope)

        'Map1.CenterAt(new ESRI.ArcGIS.ADF.Web.Geometry.Point(boundingEnvelope.XMin, boundingEnvelope.YMin));

        ' Expand the bounding envelope so that it is 1/8 of the map width.  We do this instead of using
        ' Envelope.Expand because that method expands by percentage.  Since the bounding envelope of a
        ' poing geometry has a height and width of zero, expanding by any percentage will result in no
        ' change.
        Dim mapWidthSixteenth As Double = Map1.GetFullExtent().Width / 16
        boundingEnvelope = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope(boundingEnvelope.XMin - mapWidthSixteenth, boundingEnvelope.YMin - mapWidthSixteenth, boundingEnvelope.XMax + mapWidthSixteenth, boundingEnvelope.YMax + mapWidthSixteenth)
      End If

      ' Update the map's extent with the envelope
      Map1.Extent = boundingEnvelope

      ' Make sure the map has callback results
      If Map1.CallbackResults.Count > 0 Then
        ' Register a script block to update the map via the Web ADF processCallbackResult function
        System.Web.UI.ScriptManager.RegisterClientScriptBlock(Page, Me.GetType(), "updateMap", String.Format("ESRI.ADF.System.processCallbackResult('{0}');", Map1.CallbackResults.ToString().Replace("//", "////")), True)
      End If
    End If
  End Sub

  ' Retrieves the bounding box of a polygon
  Private Sub BoundingExtent(ByVal adfPolygon As ESRI.ArcGIS.ADF.Web.Geometry.Polygon, ByVal boundingBox As ESRI.ArcGIS.ADF.Web.Geometry.Envelope)
    ' Loop through all the rings of the polygon and update the bounding box to account for each vertex
    Dim i As Integer = 0
    Do While i < adfPolygon.Rings.Count
      Dim adfRing As ESRI.ArcGIS.ADF.Web.Geometry.Ring = adfPolygon.Rings(i)
      Dim j As Integer = 0
      Do While j < adfRing.Points.Count
        BoundingExtent(adfRing.Points(j), boundingBox)
        j += 1
      Loop
      i += 1
    Loop
  End Sub

  Private Sub BoundingExtent(ByVal adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point, ByVal boundingBox As ESRI.ArcGIS.ADF.Web.Geometry.Envelope)
    ' Update the passed-in envelope based on whether the passed-in point falls outside the envelope's bounds
    If adfPoint.X < boundingBox.XMin Then
      boundingBox.XMin = adfPoint.X
    End If
    If adfPoint.X > boundingBox.XMax Then
      boundingBox.XMax = adfPoint.X
    End If
    If adfPoint.Y < boundingBox.YMin Then
      boundingBox.YMin = adfPoint.Y
    End If
    If adfPoint.Y > boundingBox.YMax Then
      boundingBox.YMax = adfPoint.Y
    End If
  End Sub

  #End Region
End Class