openlayers / ol-cesium

OpenLayers - Cesium integration
http://openlayers.org/ol-cesium/
BSD 2-Clause "Simplified" License
1.01k stars 329 forks source link

Displaying a 3D globe using ol-cesium in Angular 2+ #527

Open ghost opened 6 years ago

ghost commented 6 years ago

I am investigating mapping solutions for both 2D and 3D visualization of the globe. I think I misread the documentation and I thought that OpenLayers 4.5 supported 3D views by default; it seems this is not the case :( Am I right in thinking this?

I am therefore investigating Cesium and have come across ol-cesium but am having difficulty getting this working in my Angular 5 app. The code I have looks like this:

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';

import Map from 'ol/map';
import TileLayer from 'ol/layer/tile';
import OSM from 'ol/source/OSM';
import View from 'ol/view';
import Proj from 'ol/proj';

import * as fromRoot from '../../reducers';
import * as fromMap from '../../core/store/map/reducer';
import { ViewType } from '../../core/enums/viewtype.enum';

declare var olcs: any; // no @types

@Component( {
  selector: 'cs-map',
  templateUrl: './map.component.html',
  styleUrls: [ './map.component.scss' ]
} )
export class MapComponent implements OnInit {
  viewType$: Observable<ViewType>;

  constructor( private store: Store<fromRoot.AppState> ) {
    this.viewType$ = this.store.select( fromMap.getMapView );
  }

  ngOnInit() {
    const map = new Map( {
      target: 'map',
      layers: [
        new TileLayer( {
          source: new OSM()
        } )
      ],
      view: new View( {
        center: Proj.transform([25, 20], 'EPSG:4326', 'EPSG:3857'),
        zoom: 4
      } )
    } );
    const ol3d = new olcs.OLCesium({map: map});
    ol3d.setEnabled(true);
  }
}

This is following the example code on the ol-cesium site. I am including the following files in my index.html:

<script src="/assets/scripts/Cesium.js"></script>
<script src="/assets/scripts/olcesium.js"></script>

as well as importing the various ol modules as you can see from the code above.

Unfortunately, the code ol3d.setEnabled(true); generates the following error in the browser:

ERROR TypeError: this.S.Y is not a function at new bj (olcesium.js:261)

Anyone have any idea what I might be missing?

gberaudo commented 6 years ago

You are trying to use the beta ol package right?

gberaudo commented 6 years ago

@marknorgate-tengroup, you may be interested by the newly released https://www.npmjs.com/package/olcs. It is an alpha version of OLCesium using ES6 modules.

The community is welcomed to help test this package so that in the future it can be the default.

jamesdeantv commented 6 years ago

Check out https://github.com/quentin-ol/ngx-openlayers/issues/130 . There you will find a solution for display ol-cesium as a 3D globe. It also has integration with angular 5.

bbehling commented 6 years ago

I've been experimenting with this in Angular 5 CLI. The steps that worked for me were to install the ol-cesium npm package, add the scripts to the angular.json file

"assets": [
              "src/favicon.ico",
              "src/assets",
              { "glob": "**/*", "input": "node_modules/ol-cesium/dist/Cesium", "output": "./" }
            ],
            "styles": [
              "src/styles.css",
              "node_modules/ol-cesium/dist/node_modules/ol/ol.css",
              "node_modules/ol-cesium/css/olcs.css"
            ],
            "scripts": [
              "node_modules/ol-cesium/dist/node_modules/@camptocamp/cesium/Build/Cesium/Cesium.js"
            ]

set the Cesium base url window['CESIUM_BASE_URL'] = '/assets/node_modules/@camptocamp/cesium/Build/Cesium';

add typings.d.ts with declare var Cesium;

So I can use Cesium native methods

 const scene = ol3d.getCesiumScene();
 scene.terrainProvider = Cesium.createWorldTerrain();

and make import statements as:

import olMap from 'ol/Map.js';
import olView from 'ol/View.js';
import OLCesium from 'ol-cesium';
const ol3d = new OLCesium({
      map: ol2d,
      target: 'map3d',
      layers: []
    });

Only sugesstion I would like to make are the namespaces for the Cesium distribution. Maybe instead of

node_modules/ol-cesium/dist/node_modules/@camptocamp/cesium/Build/Cesium/Cesium.js

use a path like

node_modules/ol-cesium/dist/Cesium/Cesium.js

It was a little confusing to figure out where the Cesium dist files where.

bbehling commented 6 years ago

After upgrading to the latest version 2.2, I'm getting the following Error:

Uncaught ReferenceError: ol is not defined at Object.ol/geom/Point.js (olcesium.js:5577) at webpack_require (olcesium.js:21) at Module../src/olcs/OLCesium.js (olcesium.js:2576) at webpack_require (olcesium.js:21) at Module../src/index.library.js (olcesium.js:126) at webpack_require__ (olcesium.js:21) at olcesium.js:85 at Object../node_modules/ol-cesium/dist/olcesium.js (olcesium.js:88) at webpack_require__ (bootstrap:76) at Object../src/app/app.component.ts (main.js:97)

gberaudo commented 6 years ago

Instead of relying on the compiled ol-cesium.js file, have you tried using directly OL-Cesium and OpenLayers source? (for Cesium you need an external script, and note that you can take the upstream one if it is more convenient for you).

bbehling commented 6 years ago

Ive brought in the ol.js file in the angular.json file

"scripts": [ "node_modules/ol-cesium/dist/node_modules/@camptocamp/cesium/Build/Cesium/Cesium.js", "node_modules/ol-cesium/dist/ol.js" ]

now I get a new error: ol_cesiumWEBPACK_IMPORTED_MODULE4default.a is not a constructor

When I inspect this block of code

const ol3d = new OLCesium({
      map: ol2d,
      target: 'map3d',
      layers: []
    });

OLCesium is an object.

How to bring olcesium into the angular project correctly?

Also, this post mentions that we don't need to add anything special to angular build files to use open layers https://stackoverflow.com/questions/48283679/use-openlayers-4-with-angular-5

bbehling commented 6 years ago

I got this working by adding olcesium.js to the assets directory and importing the ol-cesium in the component as

`import OLCesium from 'src/assets/olcesium.js';

To summarize, In angular.json, I used the Cesium steps to include Cesium and added ol.js to the scripts section. Add olcesium.js to assets directory, and use the import as described above.

EDIT Was using the wrong version of olcesium.js. Still getting same error about missing constructor.

bbehling commented 6 years ago

So I just updated to version 2.2.2. New compile errors -

ERROR in ./node_modules/ol-cesium/src/olcs/OLCesium.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/VectorSynchronizer.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/Camera.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/core.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/RasterSynchronizer.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/AbstractSynchronizer.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs' ERROR in ./node_modules/ol-cesium/src/olcs/FeatureConverter.js Module not found: Error: Can't resolve 'goog/asserts.js' in '/home/dev1/code/prototypes/olc2/node_modules/ol-cesium/src/olcs'