B4J Library jGoogleMaps library

Status
Not open for further replies.
This library is similar to B4A and B4i GoogleMaps libraries.

SS-2015-07-30_15.35.52.jpg


It is based on this open source project: https://github.com/dlsc-software-consulting-gmbh/GMapsFX/ (Apache 2 license).
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.

Updates:

V2.01 - Sets the Google Maps Javascript SDK version to 3.56. There is currently an issue with JavaFX and Google Maps v3.57. A big thank you to @Star-Dust for helping with solving this issue!
V2.00 - Depends on OpenJDK 19. Previous versions will not work.

1. OpenJDK 19.0.2 + OpenJFX 17.0.6: https://www.b4x.com/b4j/files/jdk-19.0.2.7z
2. Add to main module:
B4X:
#PackagerProperty: IncludedModules = javafx.web
#PackagerProperty: AdditionalModuleInfoString = exports com.lynden.gmapsfx;    exports com.lynden.gmapsfx.javascript;    exports com.lynden.gmapsfx.javascript.event;
#PackagerProperty: AdditionalModuleInfoString = exports com.lynden.gmapsfx.javascript.object;    exports com.lynden.gmapsfx.service.directions;    exports com.lynden.gmapsfx.service.elevation;
#PackagerProperty: AdditionalModuleInfoString = exports com.lynden.gmapsfx.service.geocoding;    exports com.lynden.gmapsfx.shapes;    exports com.lynden.gmapsfx.zoom;
3. Add reference to jOkHttpUtils2.

Tip: to fix logging encoding issues with Java 19+, add this:
B4X:
#VirtualMachineArgs: -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
#PackagerProperty: VMArgs = -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8

The standalone package will not work without steps 2 and 3.
 

Attachments

  • GoogleMapExample.zip
    2.8 KB · Views: 409
  • jGoogleMaps.zip
    199.3 KB · Views: 181
Last edited:

javiers

Active Member
Licensed User
Longtime 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
Longtime 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
Longtime 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

  • pantalla.jpg
    pantalla.jpg
    59.2 KB · Views: 1,235
Last edited:

javiers

Active Member
Licensed User
Longtime 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
Longtime 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

B4X founder
Staff member
Licensed User
Longtime 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).
 

rboeck

Well-Known Member
Licensed User
Longtime User
Next idea for infowindow: can we integrate a further possibility for the user, who maybe set some actions, when he see the information in infowindows?
 

javiers

Active Member
Licensed User
Longtime User
How you can erase a marker specifically - having several markers drawn on the map - to return to draw in another position?

Imagine a fleet management application, where different vehicles must display your position in real time ...

It's posible? Any examples?

Thanks in advance...
 
Status
Not open for further replies.
Top