15

IMPORTANT NOTE When instantiating the Cesium Object in a normal project, it does not have any properties that are prefixed with underscores (_dataSourceCollection, _dataSourceDisplay, etc). When instantiated in Drupal, however, about 40-45 properties are set on the object (all prefixed with underscores) in addition to the usual properties. This occurs in Drupal 7 or 8, and though I'm not sure if this is relevant to the problem I'm having, it was a noticeable discrepancy and thus I thought it should be shared.

I have added the Cesium library to a Drupal project by placing the file in sites/all/libraries/cesium/Cesium.js along with the Assets and Widgets folders and then also calling hook_library_info in a custom module

function cesium_library_info() {
  $libraries['cesium'] = array(
    'files' => array(
      'js' => 'Cesium.js',
    ),
    'path' => 'js',
    'library path' => libraries_get_path('cesium'),
    'version' => '1'
  );
  return $libraries;
}

I am then using hook_menu to return the following page callback:

function cesium_page()  {
  drupal_add_js(libraries_get_path('cesium') . '/Cesium.js');
  drupal_add_js(drupal_get_path('module', 'cesium') . '/js/mCesium.js');
  drupal_add_css(libraries_get_path('cesium') . '/Widgets/widgets.css');

  $page = array();

  $page['ces-container'] = array(
    '#prefix' => '<div id="myApp-cesium">',
    '#suffix' => '</div>',
    '#markup' => '<h1>Welcome to Cesium!',
  );
  return $page;
}

mCesium.js contains the code where Cesium is called from within Drupal.behaviors to attach a Viewer to my #myApp-cesium element.

Drupal.behaviors.cesium = {
  attach: function (context, settings) {

    var viewer = new Cesium.Viewer('myApp-cesium', {
        imageryProvider : new Cesium.createOpenStreetMapImageryProvider({
            url : 'http://thebestmaptiles.map.tile.com/',
        }),
        baseLayerPicker : false
    });
  }
}

This successfully creates the viewer on the appropriate element inside the main container of a Drupal page. The viewer is completely void of content, however, and the following error is found in the console:

Cesium.js:169769 Uncaught TypeError: this._dataSourceAdded is not a function

The value of "this" is not null or undefined, but seems to be the structure suggesting an incompletely formed Viewer object. This object is missing all the properties which would be prefixed with underscores, such as _dataSourceAdded.

Does anyone have any insight into why this might be?

Lastly, just prior to posting this, I saw that there is a Drupal module for Cesium which has something interesting happening in hook_libraries_info_alter where the Cesium codebase is being saved as public://cesium_base_url.js.

See lines 50-59 in cesium.module found at https://www.drupal.org/project/cesium

 47 function cesium_libraries_info_alter(&$libraries) {                                                                             
 48   $library = libraries_detect('cesium');                                                                                        
 49                                                                                                                                 
 50   if ($library['installed'] == TRUE) {                                                                                          
 51     $data = "var CESIUM_BASE_URL = '" . url($library['library path'] . '/Build/Cesium/') . "';";                                
 52     $jsfile = file_unmanaged_save_data($data, 'public://cesium_base_url.js', FILE_EXISTS_REPLACE);                              
 53                                                                                                                                 
 54     $libraries['cesium']['files']['js'][$jsfile] = array(                                                                       
 55       'data' => $jsfile,                                                                                                        
 56       'weight' => 0,                                                                                                            
 57       'group' => JS_LIBRARY,                                                                                                    
 58     );                                                                                                                          
 59   }                                                                                                                             
 60 }            

I'm unsure if that approach is related whatsoever, but I thought it was worth mentioning for the off chance that it is. In any case, I should also mention that I tried a fresh project to test if that module would work, but I believe the code to download the library has to be updated.

EDIT

I'd also like to mention that I've replicated the same situation, with the same error, on both Drupal 7 and Drupal 8.

Here is the code, as loaded without Drupal.behaviors, which, again, creates the same situation with an incompetely loaded Cesium.Viewer object:

setTimeout(function() {

    var viewer = new Cesium.Viewer('myApp-cesium', {
        imageryProvider : new Cesium.createOpenStreetMapImageryProvider({
            url : 'http://thebestmaptiles.map.tile.com/',
        }),
        baseLayerPicker : false
    });
}, 5000);

ANOTHER UPDATE:

Placing the javascript inside a jQuery wrapper doesn't seem to offer any benefit.

I've also tried to see if adding the libraries in a hook_init() function would help, but it does not.

ANOTHER UPDATE:

Notable Discrepancies - Viewer Object in HelloWorld App vs Drupal

Environment Variables for Observations:

I am sending "this" to console.log inside the Viewer function of Cesium.js, AFTER all the private properties have been set (properties prefixed with an _underscore), and just prior to calling the _dataSourceAdded function on the Viewer object (line 169769 on my modified, unminified Cesium.js)

console.log(this);
var dataSourceLength = dataSourceCollection.length;
for (var i = 0; i < dataSourceLength; i++) {
    this._dataSourceAdded(dataSourceCollection, dataSourceCollection.get
   (i));          

Here are the main differences:

HelloWorld App - 41 properties (according to console.log(Object.keys(this).length);)

  • Recognized as a "Viewer" object

  • Looping over "key in obj" found 61 properties

  • 53 of these were private

Drupal App - 41 properties (Object.keys(this).length))

  • Recognized as "Object" object

  • Looping over "key in obj" found 61 properties

  • 0 of these were private

Emmanuel Buckshi
  • 558
  • 1
  • 7
  • 23
  • One piece of your code above says `var viewer = Cesium.Viewer...`. You're missing a `new` keyword here. `var viewer = new Cesium.Viewer...` – emackey Oct 03 '16 at 17:23
  • You're right! Adding "new" greatly reduces the number of properties on the object, although it is still not loading datasources and is still missing any private properties. I will update my question very soon. Thanks again! – Emmanuel Buckshi Oct 03 '16 at 19:29
  • Yup, that fixed it! Please post something as an answer so I can give you those bounty points. What a silly thing to have missed.. so glad you caught it. – Emmanuel Buckshi Oct 04 '16 at 02:23

2 Answers2

4

The code above originally had this line to create a viewer:

var viewer = Cesium.Viewer('myApp-cesium',

It was missing the new keyword:

var viewer = new Cesium.Viewer('myApp-cesium',

The new keyword is needed to correctly construct a new instance of the Cesium viewer. For details on what new does exactly, see this answer on Stack Overflow.

Community
  • 1
  • 1
emackey
  • 11,818
  • 2
  • 38
  • 58
3

Some progress made on this. It turns out, each of the Assets/Widgets/Workers directories had to be located within libraries/cesium/Build/Cesium/

Now, the globe appears normally and seems to be functioning (need to test to see if there are limitations). The "this._dataSourceAdded is not a function" error still remains, however, though it doesn't seem to be causing any issues as far as I can yet tell.

I will update after more testing.

Emmanuel Buckshi
  • 558
  • 1
  • 7
  • 23
  • Update: All functionality seems to be normal until I try and load a datasource. The data in the datasource looks just fine, but no features get built on the map. – Emmanuel Buckshi Sep 12 '16 at 19:46
  • The only other reference I've seen to this error: https://groups.google.com/forum/#!msg/cesium-dev/MAVRdeFWYjk/s31zbc9tAQAJ – Emmanuel Buckshi Sep 13 '16 at 04:05
  • Update: I tried running the code without Drupal.behaviors. Instead I simply placed it inside a setTimeout function, but it still results in the same error message. At least we can assume that Drupal.behaviors has nothing to do with the problem. – Emmanuel Buckshi Sep 15 '16 at 04:32