olcs
Version:
OpenLayers Cesium integration and plugin library
548 lines • 43.7 kB
JavaScript
import olGeomPoint from 'ol/geom/Point.js';
import { getTransform } from 'ol/proj.js';
import olcsAutoRenderLoop from './AutoRenderLoop.js';
import olcsCamera from './Camera.js';
import olcsOverlaySynchronizer from './OverlaySynchronizer.js';
import olcsRasterSynchronizer from './RasterSynchronizer.js';
import olcsVectorSynchronizer from './VectorSynchronizer.js';
import { ol4326CoordinateToCesiumCartesian } from './core.js';
import { imageRenderingValue, supportsImageRenderingPixelated } from './util.js';
/**
* Moved from Cesium
* The state of a BoundingSphere computation being performed by a {@link Visualizer}.
*/
const BoundingSphereState = {
/**
* The BoundingSphere has been computed.
*/
DONE: 0,
/**
* The BoundingSphere is still being computed.
*/
PENDING: 1,
/**
* The BoundingSphere does not exist.
*/
FAILED: 2,
};
/**
* @typedef {Object} OLCesiumOptions
* @property {import('ol/Map.js').default} map The OpenLayers map we want to show on a Cesium scene.
* @property {Element|string} [target] Target element for the Cesium scene.
* @property {function(!import('ol/Map.js').default, !Cesium.Scene, !Cesium.DataSourceCollection): Array<import('olcs/AbstractSynchronizer.js').default>}
* [createSynchronizers] Callback function which will be called by the {@link olcs.OLCesium}
* constructor to create custom synchronizers. Receives an `ol.Map` and a `Cesium.Scene` as arguments,
* and needs to return an array of {@link import('olcs/AbstractSynchronizer.js').default}.
* @property {function(): Cesium.JulianDate} [time] Control the current time used by Cesium.
* @property {boolean} [stopOpenLayersEventsPropagation] Prevent propagation of mouse/touch events to
* OpenLayers when Cesium is active.
* @property {Cesium.SceneOptions} [sceneOptions] Allows the passing of property value to the
* `Cesium.Scene`.
*/
export default class OLCesium {
autoRenderLoop_ = null;
map_;
time_;
to4326Transform_;
resolutionScale_ = 1.0;
canvasClientWidth_ = 0.0;
canvasClientHeight_ = 0.0;
resolutionScaleChanged_ = true; // force resize
container_;
isOverMap_;
canvas_;
enabled_ = false;
pausedInteractions_ = [];
hiddenRootGroup_ = null;
scene_;
camera_;
globe_;
dataSourceCollection_;
dataSourceDisplay_;
/** Time of the last rendered frame, as returned by `performance.now()`. */
lastFrameTime_ = 0;
/** The identifier returned by `requestAnimationFrame`. */
renderId_;
/** Target frame rate for the render loop. */
targetFrameRate_ = Number.POSITIVE_INFINITY;
/** If the Cesium render loop is being blocked. */
blockCesiumRendering_ = false;
/** If the warmup routine is active. */
warmingUp_ = false;
trackedFeature_ = null;
trackedEntity_ = null;
entityView_ = null;
needTrackedEntityUpdate_ = false;
boundingSphereScratch_ = new Cesium.BoundingSphere();
synchronizers_;
refresh2DAfterCameraMoveEndOnly = false;
moveEndRemoveCallback_;
constructor(options) {
this.map_ = options.map;
this.time_ =
options.time ||
function () {
return Cesium.JulianDate.now();
};
/**
* No change of the view projection.
*/
this.to4326Transform_ = getTransform(this.map_.getView().getProjection(), 'EPSG:4326');
const fillArea = 'position:absolute;top:0;left:0;width:100%;height:100%;touch-action:none;';
this.container_ = document.createElement('DIV');
const containerAttribute = document.createAttribute('style');
containerAttribute.value = `${fillArea}visibility:hidden;`;
this.container_.setAttributeNode(containerAttribute);
let targetElement = options.target || this.map_.getViewport();
if (typeof targetElement === 'string') {
targetElement = document.getElementById(targetElement);
}
targetElement.appendChild(this.container_);
/**
* Whether the Cesium container is placed over the ol map.
* a target => side by side mode
* no target => over map mode
*/
this.isOverMap_ = !options.target;
if (this.isOverMap_ && options.stopOpenLayersEventsPropagation) {
const overlayEvents = [
'click',
'dblclick',
'mousedown',
'touchstart',
'pointerdown',
'mousewheel',
'wheel',
];
for (let i = 0, ii = overlayEvents.length; i < ii; ++i) {
this.container_.addEventListener(overlayEvents[i], (evt) => evt.stopPropagation());
}
}
this.canvas_ = document.createElement('canvas');
const canvasAttribute = document.createAttribute('style');
canvasAttribute.value = fillArea;
this.canvas_.setAttributeNode(canvasAttribute);
if (supportsImageRenderingPixelated()) {
// non standard CSS4
this.canvas_.style['imageRendering'] = imageRenderingValue();
}
this.canvas_.oncontextmenu = function () {
return false;
};
this.canvas_.onselectstart = function () {
return false;
};
this.container_.appendChild(this.canvas_);
const sceneOptions = options.sceneOptions !== undefined
? { ...options.sceneOptions, canvas: this.canvas_, scene3DOnly: true }
: { canvas: this.canvas_, scene3DOnly: true };
this.scene_ = new Cesium.Scene(sceneOptions);
const sscc = this.scene_.screenSpaceCameraController;
if (!Array.isArray(sscc.tiltEventTypes)) {
console.log('sscc is not an array');
}
else {
sscc.tiltEventTypes.push({
'eventType': Cesium.CameraEventType.LEFT_DRAG,
'modifier': Cesium.KeyboardEventModifier.SHIFT,
});
sscc.tiltEventTypes.push({
'eventType': Cesium.CameraEventType.LEFT_DRAG,
'modifier': Cesium.KeyboardEventModifier.ALT,
});
}
sscc.enableLook = false;
this.scene_.camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;
this.camera_ = new olcsCamera(this.scene_, this.map_);
this.globe_ = new Cesium.Globe(Cesium.Ellipsoid.WGS84);
this.globe_.baseColor = Cesium.Color.WHITE;
this.scene_.globe = this.globe_;
this.scene_.skyAtmosphere = new Cesium.SkyAtmosphere();
// The first layer of Cesium is special; using a 1x1 transparent image to workaround it.
// See https://github.com/AnalyticalGraphicsInc/cesium/issues/1323 for details.
const firstImageryProvider = new Cesium.SingleTileImageryProvider({
tileHeight: 1,
tileWidth: 1,
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
rectangle: Cesium.Rectangle.fromDegrees(0, 0, 1, 1), // the Rectangle dimensions are arbitrary
});
this.globe_.imageryLayers.addImageryProvider(firstImageryProvider, 0);
this.dataSourceCollection_ = new Cesium.DataSourceCollection();
this.dataSourceDisplay_ = new Cesium.DataSourceDisplay({
scene: this.scene_,
dataSourceCollection: this.dataSourceCollection_,
});
this.synchronizers_ = options.createSynchronizers
? options.createSynchronizers(this.map_, this.scene_, this.dataSourceCollection_)
: [
new olcsRasterSynchronizer(this.map_, this.scene_),
new olcsVectorSynchronizer(this.map_, this.scene_),
new olcsOverlaySynchronizer(this.map_, this.scene_),
];
// Assures correct canvas size after initialisation
this.handleResize_();
for (let i = this.synchronizers_.length - 1; i >= 0; --i) {
this.synchronizers_[i].synchronize();
}
const eventHelper = new Cesium.EventHelper();
eventHelper.add(this.scene_.postRender, OLCesium.prototype.updateTrackedEntity_, this);
this.moveEndRemoveCallback_ = this.scene_.camera.moveEnd.addEventListener(() => {
if (this.refresh2DAfterCameraMoveEndOnly) {
this.camera_.checkCameraChange();
}
});
}
/**
* Destroys the Cesium resources held by this object.
*/
destroy() {
cancelAnimationFrame(this.renderId_);
this.renderId_ = undefined;
this.synchronizers_.forEach((synchronizer) => synchronizer.destroyAll());
this.camera_.destroy();
this.scene_.destroy();
// @ts-ignore TS2341
this.scene_._postRender = null;
this.moveEndRemoveCallback_();
this.container_.remove();
}
/**
* Render the Cesium scene.
*/
render_() {
// if a call to `requestAnimationFrame` is pending, cancel it
if (this.renderId_ !== undefined) {
cancelAnimationFrame(this.renderId_);
this.renderId_ = undefined;
}
// only render if Cesium is enabled/warming and rendering hasn't been blocked
if ((this.enabled_ || this.warmingUp_) && !this.blockCesiumRendering_) {
this.renderId_ = requestAnimationFrame(this.onAnimationFrame_.bind(this));
}
}
/**
* Callback for `requestAnimationFrame`.
* @param {number} frameTime The frame time, from `performance.now()`.
*/
onAnimationFrame_(frameTime) {
this.renderId_ = undefined;
// check if a frame was rendered within the target frame rate
const interval = 1000.0 / this.targetFrameRate_;
const delta = frameTime - this.lastFrameTime_;
if (delta < interval) {
// too soon, don't render yet
this.render_();
return;
}
// time to render a frame, save the time
this.lastFrameTime_ = frameTime;
const julianDate = this.time_();
// initializeFrame private property
// @ts-ignore TS2341
this.scene_.initializeFrame();
this.handleResize_();
this.dataSourceDisplay_.update(julianDate);
// Update tracked entity
if (this.entityView_) {
const trackedEntity = this.trackedEntity_;
// getBoundingSphere private property
// @ts-ignore TS2341
const trackedState = this.dataSourceDisplay_.getBoundingSphere(trackedEntity, false, this.boundingSphereScratch_);
if (trackedState === BoundingSphereState.DONE) {
this.boundingSphereScratch_.radius = 1; // a radius of 1 is enough for tracking points
this.entityView_.update(julianDate, this.boundingSphereScratch_);
}
}
this.scene_.render(julianDate);
if (!this.refresh2DAfterCameraMoveEndOnly) {
this.camera_.checkCameraChange();
}
// request the next render call after this one completes to ensure the browser doesn't get backed up
this.render_();
}
updateTrackedEntity_() {
if (!this.needTrackedEntityUpdate_) {
return;
}
const trackedEntity = this.trackedEntity_;
const scene = this.scene_;
// getBoundingSphere private property
// @ts-ignore TS2341
const state = this.dataSourceDisplay_.getBoundingSphere(trackedEntity, false, this.boundingSphereScratch_);
if (state === BoundingSphereState.PENDING) {
return;
}
scene.screenSpaceCameraController.enableTilt = false;
const bs = state !== BoundingSphereState.FAILED
? this.boundingSphereScratch_
: undefined;
if (bs) {
bs.radius = 1;
}
this.entityView_ = new Cesium.EntityView(trackedEntity, scene, scene.mapProjection.ellipsoid);
this.entityView_.update(this.time_(), bs);
this.needTrackedEntityUpdate_ = false;
}
handleResize_() {
let width = this.canvas_.clientWidth;
let height = this.canvas_.clientHeight;
if (width === 0 || height === 0) {
// The canvas DOM element is not ready yet.
return;
}
if (width === this.canvasClientWidth_ &&
height === this.canvasClientHeight_ &&
!this.resolutionScaleChanged_) {
return;
}
let resolutionScale = this.resolutionScale_;
if (!supportsImageRenderingPixelated()) {
resolutionScale *= window.devicePixelRatio || 1.0;
}
this.resolutionScaleChanged_ = false;
this.canvasClientWidth_ = width;
this.canvasClientHeight_ = height;
width *= resolutionScale;
height *= resolutionScale;
this.canvas_.width = width;
this.canvas_.height = height;
this.scene_.camera.frustum.aspectRatio =
width / height;
}
getCamera() {
return this.camera_;
}
getOlMap() {
return this.map_;
}
getOlView() {
const view = this.map_.getView();
console.assert(!!view);
return view;
}
getCesiumScene() {
return this.scene_;
}
getDataSources() {
return this.dataSourceCollection_;
}
getDataSourceDisplay() {
return this.dataSourceDisplay_;
}
getEnabled() {
return this.enabled_;
}
/**
* Enables/disables the Cesium.
* This modifies the visibility style of the container element.
* @param enable
*/
setEnabled(enable) {
if (this.enabled_ === enable) {
return;
}
this.enabled_ = enable;
// some Cesium operations are operating with canvas.clientWidth,
// so we can't remove it from DOM or even make display:none;
this.container_.style.visibility = this.enabled_ ? 'visible' : 'hidden';
let interactions;
if (this.enabled_) {
this.throwOnUnitializedMap_();
if (this.isOverMap_) {
interactions = this.map_.getInteractions();
interactions.forEach((el, i, arr) => {
this.pausedInteractions_.push(el);
});
interactions.clear();
this.map_.addInteraction = (interaction) => this.pausedInteractions_.push(interaction);
this.map_.removeInteraction = (interaction) => {
let interactionRemoved = false;
this.pausedInteractions_ = this.pausedInteractions_.filter((i) => {
const removed = i !== interaction;
if (!interactionRemoved) {
interactionRemoved = removed;
}
return removed;
});
return interactionRemoved ? interaction : undefined;
};
const rootGroup = this.map_.getLayerGroup();
if (rootGroup.getVisible()) {
this.hiddenRootGroup_ = rootGroup;
this.hiddenRootGroup_.setVisible(false);
}
this.map_.getOverlayContainer().classList.add('olcs-hideoverlay');
}
this.camera_.readFromView();
this.render_();
}
else {
if (this.isOverMap_) {
interactions = this.map_.getInteractions();
this.pausedInteractions_.forEach((interaction) => {
interactions.push(interaction);
});
this.pausedInteractions_.length = 0;
this.map_.addInteraction = (interaction) => this.map_.getInteractions().push(interaction);
this.map_.removeInteraction = (interaction) => this.map_.getInteractions().remove(interaction);
this.map_.getOverlayContainer().classList.remove('olcs-hideoverlay');
if (this.hiddenRootGroup_) {
this.hiddenRootGroup_.setVisible(true);
this.hiddenRootGroup_ = null;
}
}
this.camera_.updateView();
}
}
/**
* Preload Cesium so that it is ready when transitioning from 2D to 3D.
* @param {number} height Target height of the camera
* @param {number} timeout Milliseconds after which the warming will stop
*/
warmUp(height, timeout) {
if (this.enabled_) {
// already enabled
return;
}
this.throwOnUnitializedMap_();
this.camera_.readFromView();
const ellipsoid = this.globe_.ellipsoid;
const csCamera = this.scene_.camera;
const position = ellipsoid.cartesianToCartographic(csCamera.position);
if (position.height < height) {
position.height = height;
csCamera.position = ellipsoid.cartographicToCartesian(position);
}
this.warmingUp_ = true;
this.render_();
setTimeout(() => {
this.warmingUp_ = false;
}, timeout);
}
/**
* Block Cesium rendering to save resources.
* @param {boolean} block True to block.
*/
setBlockCesiumRendering(block) {
if (this.blockCesiumRendering_ !== block) {
this.blockCesiumRendering_ = block;
// reset the render loop
this.render_();
}
}
/**
* Render the globe only when necessary in order to save resources.
* Experimental.
*/
enableAutoRenderLoop() {
if (!this.autoRenderLoop_) {
this.autoRenderLoop_ = new olcsAutoRenderLoop(this);
}
}
/**
* Get the autorender loop.
*/
getAutoRenderLoop() {
return this.autoRenderLoop_;
}
/**
* The 3D Cesium globe is rendered in a canvas with two different dimensions:
* clientWidth and clientHeight which are the dimension on the screen and
* width and height which are the dimensions of the drawing buffer.
*
* By using a resolution scale lower than 1.0, it is possible to render the
* globe in a buffer smaller than the canvas client dimensions and improve
* performance, at the cost of quality.
*
* Pixel ratio should also be taken into account; by default, a device with
* pixel ratio of 2.0 will have a buffer surface 4 times bigger than the client
* surface.
* @param value
*/
setResolutionScale(value) {
value = Math.max(0, value);
if (value !== this.resolutionScale_) {
this.resolutionScale_ = Math.max(0, value);
this.resolutionScaleChanged_ = true;
if (this.autoRenderLoop_) {
this.autoRenderLoop_.restartRenderLoop();
}
}
}
/**
* Set the target frame rate for the renderer. Set to `Number.POSITIVE_INFINITY`
* to render as quickly as possible.
* @param {number} value The frame rate, in frames per second.
*/
setTargetFrameRate(value) {
if (this.targetFrameRate_ !== value) {
this.targetFrameRate_ = value;
// reset the render loop
this.render_();
}
}
/**
* Set if the synchronization back to the OL 2D map happens continuously or only after the camera is at rest again.
* @param {boolean} value true: synch after camera move end only; false: synch continuously
*/
setRefresh2DAfterCameraMoveEndOnly(value) {
this.refresh2DAfterCameraMoveEndOnly = value;
}
/**
* Check if OpenLayers map is not properly initialized.
*/
throwOnUnitializedMap_() {
const map = this.map_;
const view = map.getView();
const center = view.getCenter();
if (!view.isDef() || isNaN(center[0]) || isNaN(center[1])) {
throw new Error(`The OpenLayers map is not properly initialized: ${center} / ${view.getResolution()}`);
}
}
get trackedFeature() {
return this.trackedFeature_;
}
set trackedFeature(feature) {
if (this.trackedFeature_ !== feature) {
const scene = this.scene_;
//Stop tracking
if (!feature || !feature.getGeometry()) {
this.needTrackedEntityUpdate_ = false;
scene.screenSpaceCameraController.enableTilt = true;
if (this.trackedEntity_) {
this.dataSourceDisplay_.defaultDataSource.entities.remove(this.trackedEntity_);
}
this.trackedEntity_ = null;
this.trackedFeature_ = null;
this.entityView_ = null;
scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
return;
}
this.trackedFeature_ = feature;
//We can't start tracking immediately, so we set a flag and start tracking
//when the bounding sphere is ready (most likely next frame).
this.needTrackedEntityUpdate_ = true;
const to4326Transform = this.to4326Transform_;
const toCesiumPosition = function () {
const geometry = feature.getGeometry();
console.assert(geometry instanceof olGeomPoint);
const coo = geometry instanceof olGeomPoint ? geometry.getCoordinates() : [];
const coo4326 = to4326Transform(coo, undefined, coo.length);
return ol4326CoordinateToCesiumCartesian(coo4326);
};
// Create an invisible point entity for tracking.
// It is independent of the primitive/geometry created by the vector synchronizer.
const options = {
// @ts-ignore according to Cesium types, not possible to pass CallbackProperty
position: new Cesium.CallbackProperty((time, result) => toCesiumPosition(), false),
point: {
pixelSize: 1,
color: Cesium.Color.TRANSPARENT,
},
};
this.trackedEntity_ =
this.dataSourceDisplay_.defaultDataSource.entities.add(options);
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT0xDZXNpdW0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb2xjcy9PTENlc2l1bS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkEsT0FBTyxXQUFXLE1BQU0sa0JBQWtCLENBQUM7QUFHM0MsT0FBTyxFQUFDLFlBQVksRUFBeUIsTUFBTSxZQUFZLENBQUM7QUFFaEUsT0FBTyxrQkFBa0IsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLFVBQVUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyx1QkFBdUIsTUFBTSwwQkFBMEIsQ0FBQztBQUMvRCxPQUFPLHNCQUFzQixNQUFNLHlCQUF5QixDQUFDO0FBQzdELE9BQU8sc0JBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFDN0QsT0FBTyxFQUFDLGlDQUFpQyxFQUFDLE1BQU0sV0FBVyxDQUFDO0FBRTVELE9BQU8sRUFBQyxtQkFBbUIsRUFBRSwrQkFBK0IsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQUUvRTs7O0dBR0c7QUFDSCxNQUFNLG1CQUFtQixHQUEyQjtJQUNsRDs7T0FFRztJQUNILElBQUksRUFBRSxDQUFDO0lBQ1A7O09BRUc7SUFDSCxPQUFPLEVBQUUsQ0FBQztJQUNWOztPQUVHO0lBQ0gsTUFBTSxFQUFFLENBQUM7Q0FDVixDQUFDO0FBb0NGOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLFFBQVE7SUFDbkIsZUFBZSxHQUE4QixJQUFJLENBQUM7SUFDbEQsSUFBSSxDQUFNO0lBQ1YsS0FBSyxDQUFtQjtJQUN4QixnQkFBZ0IsQ0FBb0I7SUFDcEMsZ0JBQWdCLEdBQUcsR0FBRyxDQUFDO0lBQ3ZCLGtCQUFrQixHQUFHLEdBQUcsQ0FBQztJQUN6QixtQkFBbUIsR0FBRyxHQUFHLENBQUM7SUFDMUIsdUJBQXVCLEdBQUcsSUFBSSxDQUFDLENBQUMsZUFBZTtJQUMvQyxVQUFVLENBQWM7SUFDeEIsVUFBVSxDQUFVO0lBQ3BCLE9BQU8sQ0FBb0I7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