11 Replies Latest reply on May 6, 2016 3:34 AM by hpulkkinen RSS
    ewertonm Creator

    Trying to extend current GMaps extension to use Google Maps Heatmap Function.

    Hello Guys,

     

    I am building an App which will have a Heatmap plotted in a map. There are some options that can be used, but to start it I plan to use Google Maps API to do so. I have 2 options:

    1. Use Fusion Tables: it is simple to use but the data has to be stored into a Google Fusion Table in order to be used. The good thing is that the heatmap is Server Side Computed which can be an important point to performance.
    2. Use HeatMap Function: has more flexibility as the data can be passed dinamically but it is client side computed.

     

    I decided to go for the 2nd option but I cannot get it to work because it requires the Visualization library to be included and I do not know where I should put it. Does anyone have an idea of how to declare it? Here is what I have to include:

     

    <script type="text/javascript"
     
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=visualization&sensor=true_or_false">
    </script>

     

    For the code, I included an option into the extension's googlemap.ide file to add an option in the UI to Enable the HeatMap;

     

    'ShowHeatMap': {

                    'description': 'Show Fusion Tables HeatMap',

                    'isBindingTarget': true,

                    'defaultValue': false,

                    'baseType': 'BOOLEAN'

                    }

     

    Also included in the googlemap.runtime file the API Call (almost copied and pasted from google):

     

    if(this.getProperty('ShowHeatMap')){ 

        /* Data points defined as an array of LatLng objects */

      var heatmapData = [

       new google.maps.LatLng(37.782, -122.447),

       new google.maps.LatLng(37.782, -122.445),

       new google.maps.LatLng(37.782, -122.443),

       new google.maps.LatLng(37.782, -122.441),

       new google.maps.LatLng(37.782, -122.439),

       new google.maps.LatLng(37.782, -122.437),

       new google.maps.LatLng(37.782, -122.435),

       new google.maps.LatLng(37.785, -122.447),

       new google.maps.LatLng(37.785, -122.445),

       new google.maps.LatLng(37.785, -122.443),

       new google.maps.LatLng(37.785, -122.441),

       new google.maps.LatLng(37.785, -122.439),

       new google.maps.LatLng(37.785, -122.437),

       new google.maps.LatLng(37.785, -122.435)

      ];

      var heatmap = new google.maps.visualization.HeatmapLayer({

       data: heatmapData

      });

      heatmap.setMap(this.map);

       }

     

    Thanks a lot

    Ewerton

      • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
        ewertonm Creator

        Responding to my own questions:

         

        I eventually found how to include the google visualization library in the Google Maps extension.

         

        I had to replace the tag:

        <FileResource description="" isRuntime="true" isDevelopment="false" type="JS" url="https://maps.google.com/maps/api/js?sensor=false"/>

         

        by

         

        <FileResource type="JS" url="https://maps.googleapis.com/maps/api/js?key=MY_APP_KEY&libraries=visualization" description="" isDevelopment="false" isRuntime="true"  />

         

        Also had to create a Browser App key in the Google developer community and include my instance as an Allowed HTTP Referer.

         

        Still struggling with 2 things still:

        1. How to add my localhost to the list of Allowed Referer
        2. How to make the AppKey an input variable that has to be passed, so I can distribute the extension without distributing my AppKey.

         

        If somebody has an idea on how to do it, I appreciate any help

         

        Cheers!

        Ewerton

          • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
            cletusd Newbie

            Hi Ewerton,

             

            Did you get an answer to the second question? i.e. make the AppKey input variable?

             

            Also, did you have any problems with the '&' in the FileResource's url above?  In my case, I'm looking to extend the google maps widget to include the drawing library, and was having problems (where TWX would error out importing the extension) around specifying the &libraries parameter.

             

            Thanks!

            Cletus

              • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
                ewertonm Creator

                Hi  Cletus,

                 

                I did not get any feedback for the App key question, but I did figure out the syntax to use "&". Whenever you need to add it to an URL you have to actually add "&amp". So in your case it will be &amp;libraries=visualization"

                 

                Cheers

                Ewerton

                  • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
                    cletusd Newbie

                    Yes, thanks!  I figured it out as you need a double escape &amp;amp;  Just a single &amp; doesn't quite work alone.

                      • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
                        ewertonm Creator

                        Weird.. Mine is working  with only one escape.. Now my problem are the layers.. I add one and whenever a change the data the layer is not replaced, but a new one is added so I get layers on top of the other. Here is how it is coming out:

                         

                        http://vozdascoisas.blogspot.com.br/2015/12/alterando-uma-extensao-do-thingworx_30.html

                         

                        It is in portuguese but you can see some screenshots.

                         

                        Cheers

                          • Re: Trying to extend current GMaps extension to use Google Maps Heatmap Function.
                            hpulkkinen Explorer

                            Thank you for posting that here. I made my own version based on your code. This is what I changed:

                             

                            metadata.xml widget definition:

                            <Widget name="googlemap">

                              <UIResources>

                              <!-- Studio ONLY -->

                              <FileResource type="CSS" file="googlemap.ide.css" description="" isDevelopment="true" isRuntime="false" />

                              <FileResource type="JS" file="googlemap.ide.js" description="" isDevelopment="true" isRuntime="false" />

                              <!-- Runtime/Squeal ONLY -->

                              <FileResource type="CSS" file="googlemap.runtime.css" description="" isDevelopment="false" isRuntime="true" />

                              <FileResource type="JS" file="googlemap.runtime.js" description="" isDevelopment="false" isRuntime="true" />

                              <FileResource type="JS" url="https://maps.googleapis.com/maps/api/js?key=<YOUR APPLICATION KEY>&amp;libraries=visualization" description="This one should include the library for a heat map." isDevelopment="false" isRuntime="true" />

                              </UIResources>

                              </Widget>

                             

                            Add property definitions to googlemap.ide.js

                            'CustomLayerData': {

                                                'description' : 'CustomLayer Data source',

                                                'isBindingTarget': true,

                                                'isVisible': true,

                                                'baseType': 'INFOTABLE',

                                                'warnIfNotBoundAsTarget': false

                                            },

                            'CustomLayerDataField': {
                            'description' : 'Field which will provide data for Custom Layer',
                            'isBindingTarget': true,
                            'isVisible': true,
                            'isEditable': true,
                            'defaultValue': 'Reading',
                            'sourcePropertyName': 'CustomLayerData',
                            'baseTypeRestriction': 'NUMBER',
                            'baseType': 'FIELDNAME'
                            },
                            'CustomLayerLocationField': {
                            'description' : 'Field which will provide data for Custom Layer',
                            'isBindingTarget': true,
                            'isVisible': true,
                            'isEditable': true,
                            'defaultValue': 'location',
                            'sourcePropertyName': 'CustomLayerData',
                            'baseTypeRestriction': 'LOCATION',
                            'baseType': 'FIELDNAME'
                            },
                            'heatMapDissipating': {
                            'description' : 'Specifies whether heatmaps dissipate on zoom. When dissipating is false the radius of influence increases with zoom level to ensure that the color intensity is preserved at any given geographic location. Defaults to false.',
                            'isBindingTarget': true,
                            'isVisible': true,
                            'isEditable': true,
                            'defaultValue': false,
                            'baseType': 'BOOLEAN'
                            },
                            'heatMapOpacity': {
                            'description' : 'The opacity of the heatmap, expressed as a number between 0 and 1.',
                            'isBindingTarget': true,
                            'isVisible': true,
                            'isEditable': true,
                            'defaultValue': 0.5,
                            'baseType': 'NUMBER'
                            },
                            'heatMapRadius': {
                            'description' : 'The radius of influence for each data point, in pixels.',
                            'isBindingTarget': true,
                            'isVisible': true,
                            'isEditable': true,
                            'defaultValue': 60,
                            'baseType': 'NUMBER'
                            },

                             

                            googlemap.runtime.js define global variable heatmap in the begining:

                            var heatmap = undefined;


                            googlemap.runtime.js updatePropertyInfo case. Note how I delete the previous layer with heatmap.setMap(undefined).

                            if (updatePropertyInfo.TargetProperty === 'CustomLayerData') {

                              var customLayerDataRows = updatePropertyInfo.ActualDataRows;

                              var nRows = customLayerDataRows.length;

                              var heatmapData=[];

                              for (var rowNumber = 0; rowNumber < nRows; rowNumber++) {

                              var row = customLayerDataRows[rowNumber];

                              heatmapData[rowNumber] =

                              {location: new google.maps.LatLng(parseFloat(row[this.getProperty('CustomLayerLocationField')].latitude) , parseFloat(row[this.getProperty('CustomLayerLocationField')].longitude)), weight: parseFloat(row[this.getProperty('CustomLayerDataField')])};

                              }

                              var heatMapDissipating = this.getProperty('heatMapDissipating');

                              var heatMapGradient = this.getProperty('heatMapGradient');

                              var heatMapOpacity= this.getProperty('heatMapOpacity')

                              var heatMapRadius=this.getProperty('heatMapRadius')

                             

                              if (heatmap != undefined) {

                              heatmap.setMap(undefined) // Delete old layer

                              }

                              heatmap = new google.maps.visualization.HeatmapLayer({

                              data: heatmapData,

                              dissipating: heatMapDissipating,

                              opacity: heatMapOpacity,

                              radius: heatMapRadius

                              });

                              heatmap.setMap(this.map);

                              return;

                              }