Managing Bookmarks and Setting Extents with ArcGIS for Javascript

One of the primary features we developed into ActiveG Jayu was the ability to bookmark specific extents on the map. For those new to GIS terminology, an extent is a bounding rectangle defined by coordinate pairs, or in the case of Jayu, what you see in the browser’s viewport. With this feature, the user can bookmark an unlimited number of locations (extents) and select them whenever they’d like to return to that place on the map.

In Jayu we use Bootstrap’s btn-toolbar, btn-group, and dropdown-menu classes to create a menu with a “New Bookmark” menu item.

Jayu menu

When the user clicks “New Bookmark” we run a Javascript function that shows a Bootstrap modal window we have setup for adding the new bookmark’s name.

Capture

See Bootstrap Modals for further documentation.

After the user enters the Bookmark name (we’ll call it “Downtown”) and clicks Save, we use the ArcGIS map object’s extent property and xmin, xman, ymin, ymax to save each of the coordinates to an array.

var extent = new Array();
extent['xmin'] = esriMap.extent.xmin;
extent['xmax'] = esriMap.extent.xmax;
extent['ymin'] = esriMap.extent.ymin;
extent['ymax'] = esriMap.extent.ymax;

Next this extent array and the Bookmark name are then stored in our back end database for later retrieval. In the Javascript Save function we also add the Bookmark to the Bootstrap drop-down menu using a <ul> tag, so the user can navigate to it later.

Untitled

Once the Bookmark is saved to the database and added to the menu, the user can open the menu and click the Bookmark. Clicking the Bookmark triggers a Javascript function which retrieves the Bookmark’s data (xMin, xMax, yMin, yMax) from the database and uses ArcGIS’s geometry.Extent class to set the new extent.

var spatialReference = esriMap.spatialReference;
var extent = new esri.geometry.Extent(xMin, yMin, xMax, yMax, sr);

esriMap.setExtent(extent, true);

This code will set a new extent for the map, and viola, move the user to the saved location!

Screen shot resized

Android – Running an ArcGIS Map Offline

Many people know how to run ArcGIS on a desktop computer, and ESRI provides many tools to do so.  But what about workers in the field that need to see a map with specific objects?  Running offline maps on an Android device is an extremely useful tool and can help workers do a wide variety of things that before could only be done while sitting in an office.  Creating an offline map app on an Android device is something that is possible with the ESRI mobile API, but it can be tricky. So I will go over how to do two fundamental functions on an Android device: 1) Loading the offline map, and 2) querying at a specific location.

Required:

  • An Android Device (or emulator, I recommend GenyMotion if you go this way)
  • Android Studios (the latest version)
  • A file geodatabase, created using ArcGIS for desktop (with the desired layers that you want in the map loaded into it).
  1. Store the .geodatabase file on the physical device, remembering the folder hierarchy where it is stored.  The .geodatabase file is stored on the physical device in order to make it easier to sync/update the information. If the GIS data was stored inside of the actual application, it would be a much more lengthy process to update and change when your mapping data was changed. (Example path: /sdcard/Geodatabase/basemap.geodatabase)
  2. Create a new Android project in Android Studios, import the ArcGIS libraries and edit the build.gradle file accordingly (See: https://developers.arcgis.com/android/guide/install-and-set-up.htm for more information on how to get your Android app ready for ArcGIS maps).
  3. Place a MapView in your main layout. Match_parent for both width and height (We’ll call it mMapView)
  4. Because loading all of the layers from the .geodatabase file can take a hefty load on the device, it is good practice to run that on a separate background thread. To do this create a private class that extends AsyncTask and create a skeleton doInBackground method within it. (See bottom for full code)
  5. Instantiate an object of that private class in the onCreate method and call .execute() on it.
    
     MapView mMapView;
     Geodatabase geodatabase;
     private GeodatabaseFeatureTable geodatabaseFeatureTable;
     private FeatureLayer featureLayer;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
    
          mMapView = (MapView) findViewById(R.id.map); //Instantiates the MapView object
          LoadMap mLoadMap = new LoadMap(); //Runs the LoadMap class on another thread
          mLoadMap.execute(); //Calls the background thread
    
     }
    
    

     

  6. Remember where you put the .geodatabasefile on the device? We’re going to use that now.  To add the layers to the MapView, we need to do it one by one. First, we will find the .geodatabasefile and loop through each of the layers that are contained therein, adding them one by one to the MapView. NOTE: the extent of the map will be determined by the first layer that is added on, so keep that in mind when creating your .geodatabase file and adding layers on, due to how our file was constructed, I add them on starting from the back, to get the full extent of the map.
    private class LoadMap extends AsyncTask<Void, Void, Void> {
    
            @Override
            protected Void doInBackground(Void... params) {
    
                try { //Opens up the basemap.geodatabase file from it's location on the physical device
                    geodatabase = new Geodatabase("/sdcard/Geodatabase/basemap.geodatabase");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } finally { //Takes each layer one by one from the Geodatabase and adds it to the MapView
                    for (int i = (geodatabase.getGeodatabaseTables().size()) - 1; i >= 0; i--) {
                        geodatabaseFeatureTable = geodatabase.getGeodatabaseFeatureTableByLayerId(i);
                        featureLayer = new FeatureLayer(geodatabaseFeatureTable);
                        mMapView.addLayer(featureLayer);
                    }
                }
                return null;
            }
        }
    
  7. Once that is set up, run the app on the device that has the .geodatabase and it will loop through the layers, adding them to the view one by one. Your output should be to this:

Screenshot_2015-02-17-11-03-22

It is a very simple, but necessary, first step to getting a complicated, interactive custom ArcGIS application running on your Android device, free of any WiFi connection!  In my next blog post I will detail how to interact with the map, showing how to query objects at a point tapped on the map. Stay tuned!


 

 

ActiveG Jayu for Maximo—spatial visualization for all

Have you ever wanted to share maps of your Maximo work orders and assets with non-Maximo users?  Or ever wanted to integrate your GIS and Maximo, but were afraid of the cost and the effort to make it work? Then you’re not alone.  And that’s why we’ve created Jayu (pronounced Jah-Yoo).

ActiveG JayuJayu is a robust standalone web application specifically tailored to integrate GIS and Maximo data, making it accessible to whomever you choose. Jayu is the perfect blend of simplicity and power, giving your entire organization the access to a visual feature set based upon Maximo data.

Jayu builds upon the rich functionality of ActiveG MapEngine, and extends those tools to anyone in your organization.

Features:

  • Search Maximo Assets, Locations, Work Orders, and Service Requests
  • Create user-defined Work Order and Service Request visualizations
  • Filter work orders by Lead, Group, Dates, and more
  • Cluster work orders for better analysis
  • GIS Layer visibility controls
  • Generate work and asset lists based on location criteria

Quick Specs

  • Requires IIS 8+, SQL Server 2008 or later, Esri ArcGIS Server 10.x, and Maximo (of course).

So give us a call today to see how quickly you can be up and running with a GIS-based map for your Maximo data!

MBO Transactions: Beware the setWhere

Caution: setWhereOftentimes, creating, updating, or deleting an MBO is accompanied by other related MBO actions that should either succeed together or fail together within a single database transaction. 

For example, we recently added a feature to our mapping software that allows a user to select an asset on the map and enter meter readings for all of the active meters associated with that asset. We wanted to treat that collection of meter readings as a single bundle so that if, by chance, one of the input readings were to cause the database to fail to save, we didn’t want any of the other meter readings to save.

In the database world, this property is just one part of being ACID-compliant and is usually how people prefer their database to operate so that the database isn’t left in some partially incorrect or incomplete state. However, for performance reasons or for seeing steady progress in a long operation, it may be desirable at times to avoid transactions. Yet, this case should be rare. Always strive for transactions first and then choose to back away if needed.

Both IBM and Bruno provide some useful discussion on how child MBOs obtained via relationships from parent MBOs are contained in the same transaction as their parents.

So, for example:

// meters is a JSON array of JSON objects that holds meter data
for (int meterIndex = 0; meterIndex < meters.size(); ++meterIndex) {
    final JSONObject meterMap = (JSONObject) metersJson.get(i);
    final String meterName = (String) meterMap.get("meterName");
    final String meterReading = (String) meterMap.get("meterReading")

    // get asset meter
    final MboSetRemote assetMeters = mxSession.getMboSet("ASSETMETER");
    assetMeters.setWhere("assetnum = '" + assetNum + "' AND siteid = '" + siteId + "' AND metername = '" + meterName + "'");

    // update asset meter
    final MboRemote assetMeter = assetMeters.moveFirst();
    assetMeter.setValue("lastreading", meterReading);

    // update related measurements
    final MboSetRemote measurementSet = assetMeter.getMboSet("NEWMEASUREMENT");
    final MboRemote newMeasurement = measurementSet.add();
    newMeasurement.setValue("measuredate", today);

    assetMeters.save()
}

It should be noted that the above snippit is only a partial solution of how to correctly record meter data and has been gutted and rearranged for illustratation purposes. Notice that the call to assetMeters.save() is sufficent to persist both the assetMeter update as well as new additions to measurementSet. It is not necessary to call measurementSet.save() because the parent MBO tracks its children in the same transaction.

However, there is a major flaw in the code. Each meter reading is saved independently of the others; it is not transactional. It is tempting to push assetMeters.save() to the very end of the code outside the loop:

final MboSetRemote assetMeters = mxSession.getMboSet("ASSETMETER");

// meters is a JSON array of JSON objects that holds meter data
for (int meterIndex = 0; meterIndex < meters.size(); ++meterIndex) {
    ...

    // get asset meter
    assetMeters.setWhere("assetnum = '" + assetNum + "' AND siteid = '" + siteId + "' AND metername = '" + meterName + "'");

    ...
}
assetMeters.save()

Unfortunately, this fails to save meter data except for the very last meter. This leads to a crucial observation: even though assetMeters is declared above the loop, the setWhere() call resets the transaction. We must call setWhere() only once on the MBOSetRemote on which we will call save().

The corrected code looks like this:

final MboSetRemote assetMeters = mxSession.getMboSet("ASSETMETER");
final String meterList = "'meter1', 'meter2', 'meter3'";
assetMeters.setWhere("assetnum = '" + assetNum + "' AND siteid = '" + siteId + "' AND metername in (" + meterList +")";

for (MboRemote assetMeter = assetMeters.moveFirst(); assetMeter != null; assetMeter = assetMeters.moveNext()) {
    ...
}
assetMeters.save()

meterList is a String that is built up by iterating through the meters array. We also iterate through the actual MBOs instead of the meters (and reference a new map not shown to get the JSON data passed in).

The main point is that setWhere() is only called once to prevent new transactions from being saved. However, building up meterList is not ideal.

Another approach to do this, as noted by Chon, is to create assetMeters using a child relationship of some other MBO (e.g., an Asset) from another MBO set (e.g., an Asset set).  This would obviate the need to build up the meterList.  Instead of calling assetMeters.save(), we could call save() on the parent MBO set (AssetSet).

This approach would like:

final MboSetRemote assetSet = mxSession.getMboSet("ASSET");         
assetSet.setWhere("assetnum = '" + assetNum + "' AND siteid = '" + siteId + "'");
final MboRemote asset = assetSet.moveFirst();            
            
if (asset != null) {
    final MboSetRemote assetMeters = asset.getMboSet("ACTIVEASSETMETER");            
    for (MboRemote assetMeter = assetMeters.moveFirst(); assetMeter != null; assetMeter = assetMeters.moveNext()) {
        ...
    }
}
assetSet.save()

Replace Zoom In and Out Buttons for ArcGIS Javascript

Last year we finished a new product that integrates ESRI’s ArcGIS maps to Maximo. But unlike our flagship product, MapEngine, this new product can be run from outside of Maximo using any browser. We developed this so non-Maximo users such as managers would have access to the GIS and GIS-related Maximo data (like asset and work order physical locations).

One of the main requirements for this new product was a simpler, more modern interface. In implementing this we had to hide many of ArcGIS’s canned visual components and replace them with our own. We chose Twitter’s Bootstrap CSS library for its cross-browser compatibility and current styles. One ArcGIS component that needed to be replaced were the Zoom In and Zoom Out buttons. Here I am going to step you through the process of hiding the default buttons and replacing them with Bootstrap buttons.

First, we need to hide the default ArcGIS for Javascript buttons. To do this you can either set the slider to false when the map object is created:

var esriMap = new esri.Map("map", {
slider: false
}

Or hide the slider after the map object after creation:

esriMap.hideZoomSlider();

Now that the default Zoom Slider is hidden from the map, we can add our own. We’re using Bootstrap’s Toolbar and Button components but you can use any CSS library or your own for that matter. Our HTML and CSS look something like this:

HTML
Zoom In and Out HTML

CSS
Capture3

As the CSS shows, we chose to place our Zoom buttons in the bottom right corner. Our buttons look like this:

Zoom In and Out Buttons

Zoom In and Out Buttons

Once the buttons are added we need to add the event handlers that the buttons will use to Zoom In and Out. This took me a bit of time to figure out how to tell the map to Zoom In and Out, because ESRI chose to call the different Zooms “levels.” So we use the API’s setLevel function to zoom the map in and out one level at a time. Be sure this code is added after the map is created.

Zoom In and Out Event Handler

Once the setLevel functions are set using jQuery’s click event and an anonymous function, clicking the plus and minus buttons will zoom the map in and out one level at a time.

Stay tuned for further front-end tips of using ESRI’s ArcGIS for Javascript API.

ActiveG at Spring 2014 Maximo Utility Working Group (MUWG)

ActiveG is a proud participant at Maximo Utility Working Group’s (MUWG) Spring 2014 Workshop, in Sarasota, FL, May 5-7, 2014.

If you’re attending the workshop, stop by the ActiveG booth to see the latest spatial goodness for core Maximo and mobile Maximo.

The MAXIMO Utility Working Group (MUWG) is an industry group representing over 145 utility companies, counties and cities throughout the U.S., Canada, China, South Africa, Pakistan, Japan, and the Caribbean that exchange information related to the implementation and application of the MAXIMO asset management system. Two workshops are held each year, one in the Spring/Summer, the other in Fall/Winter. If you are a licensed MAXIMO user and meet the criteria of the charter you can attend a workshop.

For more information, check out the MUWG site: http://muwg.org/

To register, go to: http://muwg.org/register.

 

Tube Lines selects ActiveG MapEngine

Tube Lines Limited (London, UK) and their implementation partner Enterprise AMS Group have selected ActiveG™ MapEngine™ as the spatial integration for Tube Lines’ IBM Maximo 7.5 system, as a key component of their Asset Management Improvement Program (AMIP).

Courtesy Tube Lines Limited

MapEngine will deliver advanced spatial integration of Tube Lines’ Intergraph GIS maps in their Maximo enterprise asset management (EAM) system, providing users with dynamic visualization and map-based creation of work orders, service requests, routes, and more.

“The seamless integration of the existing GIS system by literally taking it inside of Maximo 7.5 will enable our Planners to create maintenance work packages using spatial information. This will make better use of the very limited maintenance window that is available each night by reducing walking time between jobs.

It will also enable our Strategic Planners to visually see the interaction between different asset classes at any given location. For example, we can see how poor condition drainage assets affect the performance of track and signaling assets. This information will inform decisions about major renewals and ensure that investment is targeted in the areas that will have the biggest impact on the overall performance of the railway”

James Foley, Implementation Manager, Tube Lines AMIP Program

For more information on how MapEngine can improve your Maximo experience, contact ActiveG today.

About Tube Lines

Tube Lines Limited focuses on maintaining, renewing and upgrading the Jubilee, Northern and Piccadilly Lines to speed up travel for 1.9 million people every day in the heart of London.

Tube Lines is a wholly-owned subsidiary of Transport for London and has been since 2010. They’re responsible for delivering the engineering and modernization program on its lines. They work in partnership with London Underground, which is responsible for the overall strategy and management of the Tube network including the operation of train services, ticketing, fares and travelcards, timetables and the closure of lines and stations.

Tube Lines Limited maintain, renew and upgrade over 320km of track, 254 points and crossings, 255 trains, 100 stations, 4,314 bridges and structures, 80km of embankments and cuttings, 231 escalators and 110 lifts. It’s a massive 41% of the entire Tube network. And it’s a huge responsibility. With over 500 million passenger journeys made each year on its network, safety, reliability and high performance are key to what they do.

About ActiveG

ActiveG provides innovative, advanced spatial software solutions for companies running IBM Maximo, delivering complete integration of your Enterprise Geographic Information System (GIS) with the Maximo product line, via its MapEngine™ and InformME™ solutions.

ActiveG at GOMaximo 2013

GOMAXIMOActiveG is a proud sponsor of this year’s Global Maximo Oil/Gas User Group meeting (GOMaximo) in Houston, Texas, October 2-4, 2013.

The Global Maximo Oil/Gas User Group (GOMaximo) is a non-profit organization governed by IBM
Maximo customers from around the world, formed as a network and forum for oil and gas users to share and exchange information, ideas, best practices, methods, and experiences.

GOMaximo members enjoy year-round benefits, including education, networking, benchmarking and best practices, influence programs, community engagement, and knowledge sharing. Whether your responsibilities are business management or IT support, every professional in the IBM Maximo Oil and Gas ecosystem stands to benefit from GOMaximo, regardless of company size, industry segment, or expertise.

For more information, check out the GOMaximo site: http://tivoli-ug.org/ug/global/210/

To register, go to: http://www.eventbrite.com/event/7511468003/

ActiveG InformME Wins IBM Tivoli Best of Show Award

AIBM Business Partner Award - Best of ShowctiveG won the IBM Tivoli Best of Show Award for its InformME product on March 2, 2013 at the IBM Pulse Convention in Las Vegas, NV.  ActiveG displayed InformME’s ability to create and manage work orders and assets visually, in a mobile environment.

During the competition involving 10 other IBM Business Partner solutions, ActiveG’s team demonstrated how InformME, built on the Interloc Mobile Informer platform, helps mobile users organize work based on location in disconnected GIS environment.  The judges were impressed with InformME’s ability to create and update linear work orders by drawing on the mobile map to mark the areas of work, and then see that information replicated in core Maximo.

activeG_receives_best_of_show

ActiveG Supreme Commander, Don Anderson, accepts the 2013 IBM Tivoli Best of Show award from IBM’s Mark Register.

For more information on how ActiveG InformME can help your company improve its mobility solutions with map-based visualization in connected and disconnected environments, see the InformME page, or contact ActiveG today.