Introduction

The concept of sites means that we have a dataset with list of locations which we want to show in a map with list of the locations with images showing view of the locations and so on. The target report view should look like this:

Map configuration

In order to display the side list with locations, map has to have "Show attribute values list" checked in the map settings and Value title and Value description has to be selected. If we want to show image in the list, then Image formula needs to be supplied. It can look like this:

  def imageId = crossValue('CONSTRUCTION_SITES', 'L_IMAGE_LASTVALUE') as String
  if (imageId == null || imageId == '') {
  	return '/bi/media:showimage/'+45;
  }
return '/bi/media:showimage/'+imageId;    

Edit button

Additional buttons like the edit button in the image above can be added using Actions formula:

//importFromExt(User group management,AreaFunctions)
def id = L_SITE_ID_FIRSTVALUE as String
def areaId = L_AREA_FIRSTVALUE as String
if (id != 'NaN' && areaId != 'NaN') {
  if (AreaFunctions.isSiteAdmin(id,areaId)) {
  	return [[icon:'edit',link:'report:sitedetail?ID='+id]]
  }
  if (AreaFunctions.isSiteUser(id, areaId)) {
    return []
  }
}
return false

This formula can either return array of actions or false. When it returns false, site is not displayed at all in the list. Otherwise the list of actions is list of objects with properties icon and link. Icon is suffix to "icon-" classes available in the system, so to use other just look around Belladati and see what's available. The link propery follow the generic link notation, in this case pointing to another report.

Search and Add site

These are positioned elements from outside of the map. Search is standard maps variables filter and Add site is an action button added as another view in the report after the map. The "After Javascript" in report settings is then used to move these 2 elements into the side list:

<script>  
  window.afterEditMapEntryEndpoint = '/endpoint/editMapEntryPoint'
  
  BDConfig.postInitCallbacks.push(function($) {    
  $(window).on('t5:zone:did-update', function(e) {    
    var buttons = $('.viewContentInnerLayout .actionButtons')
    var filters = $('.viewContentInnerLayout .variablesBox')
    var members = $('.membersContainer')
    var formInFilters = members.find('form')
    if (members.length && buttons.length && filters.length && !formInFilters.length) {             
      var p = buttons.closest('.grid-stack-item')
      buttons.css({float:'right'})
      members.prepend(buttons.clone(true))
      //p.hide()
      
      $filtersForm = filters.find('form')
      $filtersForm.css({float:'left'})
      $filtersForm.find('input').attr('style','')
      $filtersForm.find('div').attr('style','')
      $filtersForm.find('p:first-child').remove()
      $filtersForm.find('div:last-child').remove()
      members.prepend($filtersForm)
      filters.closest('tr').remove()
      
      window.dispatchEvent(new Event('resize'))
    }
  })
  }) 
</script> 

window.afterEditMapEntryEndpoint is a special global callback that is invoked after GEO point is edited (see below).

Add site flow

The flow for adding site is that at first details of the site are filled in and then position of the site is defined using pointer in a map. To do so we need to setup new import form with a few special features. This is how our form looks like:

  • Area is list of areas from another dataset.
  • When ZIP code is inserted Prefecture and City are filled in. That's done using "Default values formula":

    def zip = @L_ZIP_CODE as String
    def city = @L_CITY as String
    
    if (zip != null && zip != 'NaN') {
    def rows = readDataset('SYSTEM.ZIP_CODES',1,isEqualFilter('L_ZIP_CODE',zip),null)
      
    if (rows.size() > 0) {
      def r = [:]  
      r << ['L_CITY':rows[0].getValues()['L_CITY']]
      r << ['L_PREFECTURE':rows[0].getValues()['L_PREFECTURE']]
      return r
    }
    }
    return []
  • There's a hidden field that invokes a custom endpoint that setups new GEO point in GEO datadefinition. The endpoint code is:

    mapperID = 'ConstructionSites'
    siteId = request.getParameter("L_SITE_ID")
    address = request.getParameter("L_CITY")
    lat = 0
    lng = 0
    
    try {
    res = googleGeocode(address, "...")
    
    json = JSON.fromJSONString(res)
    
    lat = json.getJSONObject("geometry")
                       .getJSONObject("location")
                       .getDouble("lat");
    lng = json.getJSONObject("geometry")
                       .getJSONObject("location")
                       .getDouble("lng");
    } catch (Exception e) {
    }
    createGeoPoint(siteId, lat, lng, mapperID)
    return Response.ok(siteId,"text/plain").build()

    This takes unique ID value site ID and city and looks up GPS coordinates and creates GEO point with name the same as Site ID. In next step we want to adjust the GEO point to precise location. That would be done by redirecting in the post submit JS:

    window.setTimeout(function() {  window.parent.openBdPopup('/bi/geo/point:editEntryByName/ConstructionSites/{formula}@L_SITE_ID{formula}')
    },1000)

    When the position is adjusted and saved, window.afterEditMapEntryEndpoint = '/endpoint/editMapEntryPoint' is invoked. Using that we can update dataset with chosen GPS values and look up prefecture this locations belongs to:

    def siteId = request.getParameter('name')
    def id = request.getParameter('id')
    def lon = request.getParameter('longtitude')
    def lat = request.getParameter('latitude')
    
    def yumake = inShape(lat+','+lon, 'Prefecture-Code-Yumake')
    def prefecture = inShape(lat+','+lon, 'Prefecture-Code')
    def earthquakeArea = inShape(lat+','+lon, 'Earthquake-Areas')
    def s = inShape(lat+','+lon, 'City-code')
    
    def filter = isEqualFilter('L_PREFECTURE_CODE', yumake);
    def row = readDataset('SYSTEM.YUMAKE_CODES', 1, filter, com.belladati.common.sort.Sort.descending('row_uid'))
    
    region = row[0].getValues()['L_YUMAKE_CODE']
    
    def updata = ['L_SITE_ID':siteId,'L_GPS':lat+','+lon,'L_AREA_CODE':s,'L_PREF_CODE':yumake,'L_PREFECTURE_CODE':prefecture,'L_REGION_CODE':region,'L_EARTHQUAKE_AREA':earthquakeArea]
    updateDataset('CONSTRUCTION_SITES',[updata],['L_SITE_ID'])
    
    return Response.ok().build()




  • No labels