Load KML file does not work with 'viewer.dataSources.add(Cesium.KmlDataSource.load'

Hi at all,
I'm a GWT SW developer. I'm implementing GWT-Cesium web and I need to implement a KML loading functionality to see it on the globe. I try to put the following:

viewer = Viewer.create(element,options);
viewer.extend(Cesium.viewerDragDropMixin);
viewer.dataSources.add(Cesium.KmlDataSource.load('prueba.kml'));

But it does not work, the kml doesn't load on the map. Y tried to drag and drop the kml above (prueba.kml) over Sandcastle demo and it works fine, you can see the kml file over the globe.

thanks a lot
Regards.

Are there any errors in the console?

After executing the next two lines:

viewer.extend(Cesium.viewerDragDropMixin);

viewer.dataSources.add(Cesium.KmlDataSource.load(‘prueba.kml’));

It launch the following error:

WARN:Log:Uncaught JavaScript exception: TypeError: DataView is not a constructor in http://127.0.0.1:8888/webapp/Cesium-1.13/Build/CesiumUnminified/Cesium.js, line 115750

com.smartgwt.client.core.JsObject$SGWT_WARN: 10:04:19.866:MMV5:WARN:Log:Uncaught JavaScript exception: TypeError: DataView is not a constructor in http://127.0.0.1:8888/webapp/Cesium-1.13/Build/CesiumUnminified/Cesium.js, line 115750

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:526)

at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:105)

at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)

at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)

at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338)

at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219)

at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)

at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:576)

at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:304)

at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid(JavaScriptHost.java:107)

at com.smartgwt.client.util.SC.logWarn(SC.java)

at com.smartgwt.client.util.LogUtil.handleOnError(LogUtil.java:35)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)

at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)

at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)

at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:293)

at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:547)

at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)

at java.lang.Thread.run(Thread.java:745)

Holy smoke. This is unbelievable. I just ran into this EXACT SAME ERROR two days ago, and thought it was one of the most bizarre things I’ve ever seen. For someone else to run into this and post about it just a couple days later is absolutely crazy.

Here’s what’s going on. DataView is a JS built-in object that allows access to ArrayBuffers (per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView ). Cesium appears to use it in four-ish places:

  • CesiumTerrainProvider.js, for parsing Quantized-Mesh terrain tiles
  • Model.js, for parsing binary GLTF files
  • KmlDataSource, for checking to see if a file is definitely a zip file
  • The third-party bundled Zip.js, also for zip file manipulation

In my case, I was trying to point Cesium at the public AGI STK Terrain server, which hosts Quantized-Mesh terrain tiles, but looks like you’ve hit one of the other uses.

So, the problem comes when you try to use Cesium in a SmartGWT application. SmartGWT appears to have a Java class called DataView as well ( https://www.smartclient.com/smartgwt-latest/javadoc/com/smartgwt/client/widgets/layout/DataView.html ). Unfortunately, SmartGWT also exposes all its “class”-like objects into the JS global namespace, and that includes its DataView class.

What that means is that the built-in JS DataView object gets overwritten by the object defining SmartGWT’s DataView class. When Cesium tries to instantiate a JS DataView so it can read a binary buffer, it’s no longer the built-in object, Cesium tries to instantiate it, it’s not what it expects, and things blow up.

My solution to this issue was incredibly hacky, but worked. In my GWT host page, I did:

var builtInDataView = window.DataView;

``

That runs before any of the GWT code is initialized, so we can safely save a reference to the real built-in DataView. Then, in my GWT code, I have:

private native void restoreDataViewObject() /*-{
    // HACK SmartGWT has a class called "DataView", and adds all its classes to the global namespaces.
    // Unfortunately, there's a built-in JS class called DataView as well, and Cesium uses it to help
    // parse quantized-mesh terrain files.  Because the built-in object gets overwritten, Cesium crashes
    // trying to parse terrain.  So, we hack around this by saving a reference to the "real" DataView
    // class before GWT loads, and restore it here.

    $wnd.DataView = $wnd.builtInDataView;
}-*/;

``

I call that before I actually try to load Cesium, thus restoring the original object. Cesium is able to do what it wants, and things work.
I suppose if someone is actually using the SmartGWT DataView class and Cesium in the same application, there’d be issues. Fortunately, we’re not.

So yeah, this is all incredibly bizarre. The bug itself is a very specific interaction between SmartGWT and Cesium, and the odds of someone else running into it and posting about it just a couple days after I hit it have to be miniscule.

Hopefully that helps you, and helps anyone else who might run into this in the future.

Mark Erikson

Hi Mark,

I did the following implementations:
1.- I put the following lines in my main html (GWT host page):
  <body>
    <script type="text/javascript">
       var builtInDataView = window.DataView;
      </script>
2.- I put the following lines in my entry point GWT class with the 'onload' method:
   
       public native void restoreDataViewObject() /*-{
          $wnd.DataView = $wnd.builtInDataView;
       }-*/;

3.- I call the method above 'restoreDataViewObject()' before creating the cesium instance:
   
   private Viewer3DMap() {
            restoreDataViewObject();
     // Load Cesium javascript library
     final CesiumConfiguration cesiumConfiguration = new CesiumConfiguration().setCesiumPath('PATH TO CESIUM LIBRARY');
      ...
     }

When I execute the three points above I still have the same problem loading KML files, with the same error:

com.smartgwt.client.core.JsObject$SGWT_WARN: 10:04:19.866:MMV5:WARN:Log:Uncaught JavaScript exception: TypeError: DataView is not a constructor in http://127.0.0.1:8888/webapp/Cesium-1.13/Build/CesiumUnminified/Cesium.js, line 115750

Does anyone help me, please??

Thanks very much!

Hmm. It certainly worked for me. Just for kicks, maybe try moving the “var builtInDataView” script tag into your instead of . As I understand it, that should force the code to run synchronously and hopefully ensure that it happens before the SmartGWT scripts load and overwrite the DataView object.

I have already moved the "var builtInDataView" script tag into my <head> instead of <body> and it does not work. I don't know how to resolve the problem. I'm going on working in the solution. I'll tell you if I find a solution for the problem.

Thanks Mark.

Hmm. Not sure what to tell you. Ultimately, the problem is that SmartGWT is overwriting the “DataView” variable in the global JS namespace. Maybe stick a breakpoint in your code right where you’re making the KmlDataSource.load() call, and check to see what that variable is at that point. If it’s a function(), it’s correct. If it’s an object with a "class: ‘DataView’ " field, it’s been overwritten by SmartGWT.

I suspect there’s still something about the sequencing between loading the SmartGWT library, loading Cesium, and running your code.

Hi Mark,

It's working fine now!...I implement your solution but to take into account the following:
1. It's necessaty to move the "var builtInDataView" script tag into the <head> section, but before the following script tag:

   "<script type="text/javascript" language="javascript" src="Module_Name/Module_Name.nocache.js"></script>"

2.-The script tag above loads your compiled module.

Thank you very much Mark. Thank you very much Mark. Without your effort it would have been impossible to solve .

Yep, as I figured - you were still loading GWT (and therefore SmartGWT) before you saved off the reference to DataView.

Glad I could help. Like I said, the odds of you running into this problem and asking about it just a couple days after I encountered and solved it myself are pretty ridiculous.