-
Notifications
You must be signed in to change notification settings - Fork 8
Imagery create new map provider
Tzahi Levi edited this page May 7, 2019
·
7 revisions
let's create a new map provider that we can supply to our imagery module.
- you need an app as describe here
or you cangit clone https://github.com/AnSyn/imagery-implementation.git
- install cesium
npm i cesium
we need to add Cesium to our build.
go to your angluar.json
file add do to following:
- add to
projects.YOUR_PROJECT_NAME.architect.build.options.assets
array this object
{
"glob": "**/*",
"input": "node_modules/cesium/Build/Cesium",
"output": "/assets/Cesium"
},
- add to
projects.YOUR_PROJECT_NAME.architect.build.options.scripts
the string"node_modules/cesium/Build/Cesium/Cesium.js"
Create a new directory called cesium
create a new file cesium/cesium-OSM-source-proveider.ts
and copy the following code to it:
import { BaseMapSourceProvider, ImageryMapSource, IBaseImageryMapConstructor, IMapSettings } from '@ansyn/imagery';
import {CesiumMap} from './cesium-map';
declare const Cesium: any;
@ImageryMapSource({
supported: [CesiumMap],
sourceType: 'OSM'
})
export class CesiumOsmSourceProvider extends BaseMapSourceProvider {
protected create(metaData: any): Promise<any> {
const cesiumOsmLayer = Cesium.createOpenStreetMapImageryProvider();
return Promise.resolve(cesiumOsmLayer);
}
}
create a new file cesium/cesium-map.ts
and copy the following code to it:
import {BaseImageryMap, ImageryMap, ImageryMapExtent, ImageryMapPosition} from '@ansyn/imagery';
import {feature, featureCollection, geometry} from '@turf/turf';
import {GeoJsonObject, Point, Polygon} from 'geojson';
import {Observable, of} from 'rxjs';
import {mergeMap} from 'rxjs/operators';
declare const Cesium: any;
Cesium.buildModuleUrl.setBaseUrl('assets/Cesium/');
export const toDegrees = (radians: number): number => {
return radians * 180 / Math.PI;
};
@ImageryMap({
mapType: 'CesiumMap',
deps: []
})
export class CesiumMap extends BaseImageryMap<any> {
element: HTMLElement;
mapObject: any;
initMap(element: HTMLElement, shadowNorthElement: HTMLElement, shadowDoubleBufferElement: HTMLElement, layer?: any, position?: ImageryMapPosition): Observable<boolean> {
this.element = element;
return this.resetView(layer, position);
}
resetView(layer: any, position: ImageryMapPosition, extent?: ImageryMapExtent): Observable<boolean> {
if (!this.mapObject) {
return this.createMapObject(layer).pipe(
mergeMap((isReady) => {
return this.setOrFit(position, extent);
}));
}
this.setOrFit(position, extent);
}
getCenter(): Observable<Point> {
const viewer = this.mapObject;
const windowPosition = new Cesium.Cartesian2(viewer.container.clientWidth / 2, viewer.container.clientHeight / 2);
const pickRay = viewer.scene.camera.getPickRay(windowPosition);
const pickPosition = viewer.scene.globe.pick(pickRay, viewer.scene);
const pickPositionCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(pickPosition);
const long = toDegrees(pickPositionCartographic.longitude);
const lat = toDegrees(pickPositionCartographic.latitude);
const point: Point = {
type: 'Point',
coordinates: [long, lat]
};
return of(point);
}
setCenter(center: Point, animation: boolean): Observable<boolean> {
const currentPosition = this.mapObject.camera.positionCartographic;
const extentFeature = feature(center);
const collection: any = featureCollection([extentFeature]);
const geoJsonCenter = collection.features[0].geometry.coordinates;
this.mapObject.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(geoJsonCenter[0], geoJsonCenter[1], currentPosition.height)
});
return of(true);
}
getRotation(): number {
return NaN;
}
createMapObject(layer: any): Observable<boolean> {
if (this.mapObject) {
this.internalDestroyCesium();
}
const viewer = new Cesium.Viewer(this.element, {
imageryLayers: layer,
baseLayerPicker: false
});
viewer.scene.globe.baseColor = Cesium.Color.BLACK;
this.mapObject = viewer;
return of(true);
}
setOrFit(position: ImageryMapPosition, extent?: ImageryMapExtent) {
if (extent) {
return this.fitToExtent(extent);
}
return this.setPosition(position);
}
_imageToGround({x, y}: { x: number, y: number }) {
const position = this.mapObject.camera.getPickRay({x, y});
const cartesian = this.mapObject.scene.globe.pick(position, this.mapObject.scene);
if (cartesian) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
return [longitude, latitude];
} else {
throw new Error('Empty Point');
}
}
internalSetPosition(extentPolygon: Polygon): Observable<boolean> {
const extentFeature = feature(extentPolygon);
const collection: any = featureCollection([extentFeature]);
const geoJsonExtent = collection.features[0].geometry;
const rec = [...geoJsonExtent.coordinates[0][0], ...geoJsonExtent.coordinates[0][2]];
this.mapObject.camera.setView({
destination: Cesium.Rectangle.fromDegrees(...rec)
});
return of(true);
}
internalDestroyCesium() {
if (this.mapObject) {
this.mapObject.destroy();
}
}
public dispose() {
this.internalDestroyCesium();
}
setPosition(position: ImageryMapPosition): Observable<boolean> {
const {extentPolygon} = position;
return this.internalSetPosition(extentPolygon);
}
getPosition(): Observable<ImageryMapPosition> {
try {
const {height, width} = this.mapObject.canvas;
const topLeft = this._imageToGround({x: 0, y: 0});
const topRight = this._imageToGround({x: width, y: 0});
const bottomRight = this._imageToGround({x: width, y: height});
const bottomLeft = this._imageToGround({x: 0, y: height});
const extentPolygon = <Polygon>geometry('Polygon', [[topLeft, topRight, bottomRight, bottomLeft, topLeft]]);
return of({extentPolygon});
} catch (error) {
return of(null);
}
}
addGeojsonLayer(data: GeoJsonObject): any {
}
addLayer(layer: any): void {
}
addLayerIfNotExist(layer: any): any {
}
getLayers(): any[] {
return [];
}
removeLayer(layer: any): void {
}
setRotation(rotation: number): void {
}
toggleGroup(groupName: string, newState: boolean): any {
}
updateSize(): void {
}
}
replace the provider inside ImageryModule in app.module.ts
...
ImageryModule.provide({
maps: [CesiumMap],
plugins: [],
mapSourceProviders: [CesiumOsmSourceProvider]
}),
],
providers: [
{
provide: MAP_PROVIDERS_CONFIG,
useValue: {
CesiumMap: {
defaultMapSource: 'OSM'
}
}
},
{
provide: MAP_SOURCE_PROVIDERS_CONFIG,
useValue: {
OSM: { }
}
}
]
...
change our Settings.mapType prop in app.component.ts
to CesiumMap
you should be see something like this