Community Tip - Stay updated on what is happening on the PTC Community by subscribing to PTC Community Announcements. X
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:
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
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:
If somebody has an idea on how to do it, I appreciate any help
Cheers!
Ewerton
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
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 "&". So in your case it will be &libraries=visualization"
Cheers
Ewerton
Yes, thanks! I figured it out as you need a double escape &amp; Just a single & doesn't quite work alone.
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
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>&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;
}
Thank you for your posting Heikki Pulkkinen
I have followed your steps to update the google maps existing extension. But I am unable to use it in the composer. I can load the extension but when I look for google maps the new properties related to heat map (such as CustomLayerDataField or HeatMapRadius) are not shown. Did you have to rename the extension? or load it in a different way?
I've seen this happening and what I did was to uninstall the Maps extension, stop tomcat, clear tomcat cache, start tomcat and then Install the extension again.
Thanks Ewerton Moreira. Re-loading the extension and restarting tomcat worked.
One more question, how are you loading the custom data for the heatmap? Are you creating a thing with the latitude/longitude data?
I would like to reuse the location data from the google heatmap example as a start.
The extension should be loading data from an Infotable that could come either from a Datatable or a Custom service. In my tests I created a Data Table, populated with some values and used the GetDataTableEntries service to populate the widget.
Cheers
Ewerton
I have multiple Things with location variables. I get their data with queryImplementingThingWithData and give it to both data and customLayerData fields in the extension.
If you don't want to create a Thing for every data point you should use an Infotable as Ewerton described.