Environment: MacOSX, RoR 3.2.6, gmaps4rails 1.5.5, Google Maps API V3
Desire: It would be nice to display polylines on a map using gmaps4rails that can support the symbols mechanism in a Google Map.
Referenced Documentation:
Google Maps API Polylines Symbols Documentation
Live example of symbols on polylines
Gmaps4Rails Documentation on Polylines
Current Status of Problem I am currently able to use the vanilla attributes (strokeColor, strokeWeight, strokeOpacity) to draw polylines utilizing gmaps4rails. The issue comes when I am trying to add the metadata for creating the symbols on the line.
Working code in Google Map
From the documentation for symbols on a polyline you create an icons array, with 1-n icon elements. An example from a working sample is:
dashed = new google.maps.Polyline({
path: [
new google.maps.LatLng(40, -80),
new google.maps.LatLng(-50, 80)
],
geodesic: true,
strokeOpacity: 0.0,
strokeColor: 'yellow',
icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'red',
strokeOpacity: 1.0,
},
repeat: '24px'
}],
map: map,
});
Where dashed is the polyline to be created and the icons array is defined inline via SVG in Javascript.
When inspecting the object within the Chrome inspection window and setting a breakpoint before the map is finalized, you get an object formatted like so (removed the generic accessors and object references):
dashed
geodesic: true
icons: Array[1]
0: Object
icon: Object
path: "M 0,-2 0,2"
strokeColor: "red"
strokeOpacity: 1
repeat: "24px"
length: 1
latLngs: Nf
map: sh
strokeColor: "yellow"
strokeOpacity: 0
This works all well and good. However it is javascript created in static html and applied in the onLoad() function.
My attempt to replicate using gmaps4rails
I have a generic map controller that loads multiple polygons, symbols, and polylines. As stated before getting generic polylines is no problem. This is the Ruby code in the controller that I am attempting to use to generate the polyline with a basic dashed symbol.
# Array to push created lines into for pushing through JSON
polyline_array = []
# Array to push the icons created into for use by the gmaps4rails.base.js.coffee
icons_array = []
# SVG path representation of symbol
symbol = {:path => 'M 0,-2 0,2', :strokeColor => 'red', :strokeOpacity => 1.0}
# Create actual instance of the icon element to push to the icons array
tmpIcon = {:icon => symbol, :repeat => '24px'}
# Push to the icons array
icons_array.push(tmpIcon)
@lines.each do |line|
tmpLine = []
line.points.each do |point|
# Only populate the icon and line style for the first point in the
# polylines point array
if point == line.points.first
tmpPoint = {:clickable => true, :linename => line.name,
:icons => icons_array, :strokeOpacity => 0.0, :strokeColor => 'yellow'}
else
tmpPoint = {}
end
tmpPoint.merge ! :lat => point.latitude, :lng => point.longitude
tmpLine.push(tmpPoint)
end
polyline_array.push(tmpLine)
end
@polyline_json = polyline_array.to_json
I made a modification to the gmaps4rails.googlemaps.js.coffee script to insert the icons into the polyline creation function.
for element in polyline
#if we have a coded array
if element.coded_array?
decoded_array = new google.maps.geometry.encoding.decodePath(element.coded_array)
#loop through every point in the array
for point in decoded_array
polyline_coordinates.push(point)
#or we have an array of latlng
else
#by convention, a single polyline could be customized in the first array or it uses default values
if element == polyline[0]
strokeColor = element.strokeColor || @polylines_conf.strokeColor
strokeOpacity = 0
# Set explicit strokeOpacity to 0 to try and match example that works
# Would do something sexy later
#strokeOpacity = element.strokeOpacity || @polylines_conf.strokeOpacity
# Comment out strokeWeight to make it match object sent in working example
#strokeWeight = element.strokeWeight || @polylines_conf.strokeWeight
clickable = element.clickable || @polylines_conf.clickable
zIndex = element.zIndex || @polylines_conf.zIndex
icons = element.icons || @polylines_conf.icons
#add latlng if positions provided
if element.lat? && element.lng?
latlng = @createLatLng(element.lat, element.lng)
polyline_coordinates.push(latlng)
# Construct the polyline
new_poly = new google.maps.Polyline
path: polyline_coordinates
strokeColor: strokeColor
strokeOpacity: strokeOpacity
# Comment out since it doesn't exist in the object since it was commented
# out above
#strokeWeight: strokeWeight
clickable: clickable
zIndex: zIndex
icons: icons
#save polyline
polyline.serviceObject = new_poly
new_poly.setMap(@serviceObject)
So that is what has been changed and how I am populating the json that drives the polyline creation.
If I inspect the "new_poly" object in Chrome by setting a breakpoint right after creation and it has been added to the map using the setMap function, this is the object that is returned (removed the generic accessors and object references).
new_poly
icons: Array[1]
0: Object
icon: Object
path: "M 0,-2 0,2"
strokeColor: "red"
strokeOpacity: 1
repeat: "24px"
length: 1
latLngs: Nf
map: xh
strokeColor: "yellow"
strokeOpacity: 0
So all that being said I have no idea what is going on. It would seem that for all intents and purposes the polyline objects being added to the map are structurally the same. Is there a phase within gmaps4rails that I am missing on how I add things to the map?
Update 1 8/21/2012 I have converted everything to use that branch. However I am getting the same issue. I have used jsfiddle to take the output from the mergedOptions object within google/objects/polyline.coffee and display the polyline as created from within gmaps4rails. On jsfiddle, it works fine, however when creating within gmaps4rails, no luck. Here is a link to the fiddle: working dashed line
So to make sure it was nothing in the map, I added the following to the gmaps4rails callback.
var icon_array = {"icons":[{"repeat":"24px","icon":{"path":"M 0,-2 0,2","strokeOpacity":1,"strokeColor":"red", "scale": 4}}],"path":[{"$a":35,"ab":-70},{"$a":40,"ab":-80},{"$a":50,"ab":-85}],"strokeColor":"yellow"};
var route1 =
[
new google.maps.LatLng(35,-70),
new google.maps.LatLng(40,-80),
new google.maps.LatLng(50, -85)
];
console.log(icon_array);
icon_array.path = route1;
var path1 = new google.maps.Polyline(icon_array);
path1.setMap(Gmaps.map.map.serviceObject);
It creates a solid yellow line instead of expected dashed line. The object passed into the new google.maps.Polyline mergedOptions line in polyline.coffee is what I used in the above JSON parse. I had to reset the path array due to there being no type information I assume when parsing from JSON, but objectively it should be correct as you have createLatLng function that creates a google lat/lng object within the polylines.coffee script from the polyline array.
It is really strange. I started looking at the options on the map as it is created, but it seems there wouldn't be anything there that could cause issues.
I determined what was the difference in how gmaps4rails created a map and how the jsFiddle was creating the map, and came to the conclusion that it was the api setting for the map api include from google.
On line 8 of ./lib/gmaps4rails/view_helper.rb there is the line:
GOOGLE = "//maps.google.com/maps/api/js?v=3.8"
If you change this line to be:
GOOGLE = "//maps.google.com/maps/api/js?"
thus removing the base version from the API call it allows for the map to display dashed lines when using gmaps4rails.
I am not sure why an explicit version call within that maps js definition would make the dashed lines not work however I am now able to utilize the custom gem to display dashed lines, and I imagine more complex SVG symbols on lines.
Thanks apneadiving for your help. I don't imagine that I would have figured this out without having downloaded the source and started digging. I imagine that this will work for the non objectify branch as well.
I will make a post on the github project as well with the findings. Thanks again, gmaps4rails has been a huge help.