B4J Library jGoogleMaps library

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User
This library is similar to B4A and B4i GoogleMaps libraries.



It is based on this open source project: http://rterp.github.io/GMapsFX/
Under the hood it uses JavaFX WebView with GoogleMaps JavaScript API V3.

Using the map is quite simple. You need to initialize GoogleMap and then wait for the Ready event.
GoogleMap.AsPane returns the pane that holds the map. You should add this pane to the nodes tree.

Once the ready event is fired you can add markers or change the position.

v1.10 - New AddPolyline method.

Example:
B4X:
Dim l1, l2, l3 As LatLng
l1.Initialize(20, 20)
l2.Initialize(25, 25)
l3.Initialize(30, 20)
gmap.AddPolyline(Array (l1, l2, l3), 4, fx.Colors.Red)
v1.20 - New AddPolygon method.

v1.21 - Fixes a crash that happens after clicking on the Google link. Note that it will cause the map to reset.

V1.50 - Based on the latest version of GMapsFX. New Initialize2 method allows setting the API key:
https://developers.google.com/maps/documentation/javascript/get-api-key#key

V1.55 - Reapplied most of the changes done by Informatix in v1.28.

V1.61 - Fixes an issue related to the API key.

V1.62 - Removed the new full screen control (which doesn't do anything in desktop apps).
V1.65 - Adds PolylineClick (SelectedPolyline As MapPolyline) event.
V1.70 - Fixes the font issue on Macs.
V1.71 - Fixes an issue with MapCircle.Radius.
V1.75 - Polygons, Polylines and Circles are only clickable if the relevant click event is handled.
V1.80 - Adds compatibility with B4JPackager11. You need to set AdditionalModuleInfoString to "exports com.lynden.gmapsfx.javascript.event;"
V1.81 - Marker.Position property is read / write property (was write only).
V1.82 - Changes the way the map is loaded internally as the previous method no longer works.

Note that due to a bug in the native WebView the map can disappear if the user drags it too fast. For that reason it is important to show a "reset map" button that resets its position.

The map will not work properly without an API key.

If you are using Java 9 then you need to call Form.Show before adding the map (https://www.b4x.com/android/forum/threads/java-9-and-webview-and-googlemaps.85353/).
 

Attachments

Last edited:

javiers

Active Member
Licensed User
Hi Erel ,
to run the program I get the following error.
Finally load the map right , but not the zoom controls shown.

a greeting

B4X:
Program started.
netscape.javascript.JSException: RangeError: Maximum call stack size exceeded.
    at com.sun.webkit.dom.JSObject.fwkMakeException(JSObject.java:128)
    at com.sun.webkit.WebPage.twkExecuteScript(Native Method)
    at com.sun.webkit.WebPage.executeScript(WebPage.java:1427)
    at javafx.scene.web.WebEngine.executeScript(WebEngine.java:948)
    at com.lynden.gmapsfx.javascript.JavaFxWebEngine.executeScript(JavaFxWebEngine.java:39)
    at com.lynden.gmapsfx.GoogleMapView.mapResized(GoogleMapView.java:101)
    at com.lynden.gmapsfx.GoogleMapView.lambda$4(GoogleMapView.java:127)
    at com.lynden.gmapsfx.GoogleMapView$$Lambda$169/448074.handle(Unknown Source)
    at com.lynden.gmapsfx.javascript.event.EventHandlers.handleStateEvent(EventHandlers.java:107)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at com.sun.webkit.Utilities.lambda$fwkInvokeWithContext$55(Utilities.java:94)
    at com.sun.webkit.Utilities$$Lambda$171/13079072.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.webkit.Utilities.fwkInvokeWithContext(Utilities.java:94)
    at com.sun.webkit.Timer.twkFireTimerEvent(Native Method)
    at com.sun.webkit.Timer.fireTimerEvent(Timer.java:83)
    at com.sun.webkit.Timer.notifyTick(Timer.java:64)
    at javafx.scene.web.WebEngine$PulseTimer.lambda$static$45(WebEngine.java:1167)
    at javafx.scene.web.WebEngine$PulseTimer$$Lambda$86/9817138.pulse(Unknown Source)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
    at com.sun.javafx.tk.Toolkit$$Lambda$152/18962425.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
    at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$40/14695809.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
    at com.sun.glass.ui.win.WinApplication$$Lambda$36/24408301.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "JavaFX Application Thread"
 

javiers

Active Member
Licensed User
The Java version is the version 8 upgrade 51.

Path configuration:
C: \ Program Files \ Java \ jdk1.8.0_51 \ bin \ javac.exe

B4J version 3.02

Is this correct?
 

javiers

Active Member
Licensed User
BJ4 I upgraded to version 3.5.
As you can see in the picture, giving the same error continues after the program starts.

Nor does it show the zoom controls as on your image.

Thanks for the answers ...

Note:
I found this on the internet ...
"It means that somewhere in your code, you are calling a function which in turn calls another function and so forth, until you hit the call stack limit.


This is almost always because of a recursive function with a base case that isn't being met."


"There is a recursive loop somewhere in your code (i.e. a function that eventually calls itself again and again until the stack is full).

Other browsers either have bigger stacks (so you get a timeout instead)"
 

Attachments

Last edited:

javiers

Active Member
Licensed User
The problem is probably in the native WebView.

What happens after this error? Does the program crash?
Does not end the program. The map and markers are shown, but not the zoom controls , map type, etc.
 

Douglas Farias

Expert
Licensed User
Here show the logs with error only
but all are working, controls zoom etc.

Program started.
netscape.javascript.JSException: RangeError: Maximum call stack size exceeded.
at com.sun.webkit.dom.JSObject.fwkMakeException(JSObject.java:128)
at com.sun.webkit.WebPage.twkExecuteScript(Native Method)
at com.sun.webkit.WebPage.executeScript(WebPage.java:1427)
at javafx.scene.web.WebEngine.executeScript(WebEngine.java:948)
at com.lynden.gmapsfx.javascript.JavaFxWebEngine.executeScript(JavaFxWebEngine.java:39)
at com.lynden.gmapsfx.GoogleMapView.mapResized(GoogleMapView.java:101)
at com.lynden.gmapsfx.GoogleMapView.lambda$4(GoogleMapView.java:127)
at com.lynden.gmapsfx.GoogleMapView$$Lambda$216/16069103.handle(Unknown Source)
at com.lynden.gmapsfx.javascript.event.EventHandlers.handleStateEvent(EventHandlers.java:107)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at com.sun.webkit.Utilities.lambda$fwkInvokeWithContext$55(Utilities.java:94)
at com.sun.webkit.Utilities$$Lambda$218/4072054.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.webkit.Utilities.fwkInvokeWithContext(Utilities.java:94)
at com.sun.webkit.Timer.twkFireTimerEvent(Native Method)
at com.sun.webkit.Timer.fireTimerEvent(Timer.java:83)
at com.sun.webkit.Timer.notifyTick(Timer.java:64)
at javafx.scene.web.WebEngine$PulseTimer.lambda$static$45(WebEngine.java:1167)
at javafx.scene.web.WebEngine$PulseTimer$$Lambda$134/26976723.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda$200/21563475.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$40/26490720.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/3326003.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
 

Erel

Administrator
Staff member
Licensed User
See this code:
B4X:
#Region  Project Attributes
   #MainFormWidth: 600
   #MainFormHeight: 400
#End Region

Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private Pane1 As Pane
   Private gmap As GoogleMap
   Private btnResetMap As Button
   Private btnJumpToEiffel As Button
   Private statusBar1 As StatusBar
   Private MarkerInfos As Map
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.SetFormStyle("UNIFIED")
   MainForm.RootPane.LoadLayout("1") 'Load the layout file.
   Dim options As MapOptions
   options.StreetViewControl = False
   gmap.Initialize("gmap", options)
   Pane1.AddNode(gmap.AsPane, 0, 0, Pane1.Width, Pane1.Height)
   MainForm.Show
   statusBar1.Initialize("")
   MainForm.RootPane.AddNode(statusBar1, 0, 0, -1, 30)
   MainForm.RootPane.SetAnchors(statusBar1, 0, -1, 0, 0)
   statusBar1.Style = "-fx-background-color: white;"
   statusBar1.Text = "Data folder: " & GetDataFolder("GoogleMap")
   MarkerInfos.Initialize
End Sub

Sub GetDataFolder (AppName As String) As String
   Dim os As String = GetSystemProperty("os.name", "").ToLowerCase
   If os.Contains("win") Then
    Dim wf As String = File.Combine(GetEnvironmentVariable("AppData", ""), AppName)
    File.MakeDir(wf, "")
    Return wf
   Else
     Return File.DirApp
   End If
End Sub   

Sub gmap_Ready
   btnResetMap.Enabled = True
   btnJumpToEiffel.Enabled = True
   For i = 1 To 10
     Dim m As Marker = gmap.AddMarker(10 * i, 10 * i, "Marker #" & i)
     AttachInfoWindow(m, "Some text " & i)
   Next
End Sub

Sub gmap_Click (Point As LatLng)
   gmap.AddMarker(Point.Latitude, Point.Longitude, "New Marker")
   Log("Click: " & Point)
End Sub

Sub gmap_MarkerClick (SelectedMarker As Marker)
   ShowInfoWindow(SelectedMarker, gmap)
End Sub

Private Sub ShowInfoWindow (Marker As Marker, Map As GoogleMap)
   If MarkerInfos.ContainsKey(Marker) Then
     Dim info As JavaObject = MarkerInfos.Get(Marker)
     Dim jMap As JavaObject = Map
     jMap = jMap.GetField("map")
     info.RunMethod("open", Array (jMap, Marker))
   End If
End Sub

Private Sub AttachInfoWindow (Marker As Marker, Text As String)
   Dim infoWindow As JavaObject
   infoWindow.InitializeNewInstance("com.lynden.gmapsfx.javascript.object.InfoWindow", Null)
   infoWindow.RunMethod("setContent", Array (Text))
   MarkerInfos.Put(Marker, infoWindow)
End Sub

Sub btnResetMap_Action
   Dim cp As CameraPosition
   cp.Initialize(0, 0, 1)
   gmap.MoveCamera(cp)
End Sub
Sub Pane1_Resize (Width As Double, Height As Double)
   gmap.AsPane.SetSize(Width, Height)
End Sub

Sub btnJumpToEiffel_Action
   gmap.MapType = gmap.MAP_TYPE_SATELLITE
   Dim cp As CameraPosition
   cp.Initialize(48.858260, 2.29517, 18)
   gmap.MoveCamera(cp)
End Sub
The relevant methods are: AttachInfoWindow and ShowInfoWindow. Don't forget to add the MarkerInfos map (and initialize it).
 

magi6162

Well-Known Member
Licensed User
thanks!!!!
how can I use jgooglemap , for :
bounds.extend ( LatLng )
map.fitBounds ( bounds )

best regards
 

magi6162

Well-Known Member
Licensed User
thank you.
I examined the lib , but there is no function for map.fitbounds.

But I could always write a similar function in b4j and using jGooglemap lib.
 
Status
Not open for further replies.
Top