@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
163 lines (148 loc) • 5.98 kB
text/typescript
import mapboxgl from 'mapbox-gl';
import {Camera} from 'three';
import {PolyScene} from '../../../engine/scene/PolyScene';
import {MapboxCameraAttribute} from './MapboxCameraAttribute';
import {MapboxLayersController, LayersOptions} from './LayersController';
import {ThreejsLayerRenderFunc} from './layers/MapboxThreejsLayer';
import {MapboxViewer} from '../../../engine/viewers/Mapbox';
// import {NodeContext} from '../../../engine/poly/NodeContext';
import {JsType} from '../../../engine/poly/registers/nodes/types/Js';
import {coreObjectClassFactory} from '../../geometry/CoreObjectFactory';
interface CreateMapboxMapOptions {
camera: Camera;
container: HTMLElement;
scene: PolyScene;
renderFunc: ThreejsLayerRenderFunc;
viewer: MapboxViewer;
}
type MapRegisterCallback = (value: mapboxgl.Map) => void;
// const CAMERA_MOVE_EVENT: Event = {
// type: 'cameraMove',
// };
class MapboxMapsControllerClass {
private static _instance: MapboxMapsControllerClass;
static instance() {
return (this._instance = this._instance || new MapboxMapsControllerClass());
}
private constructor() {}
private _scene: PolyScene | undefined;
private _mapByCameraName: Map<string, mapboxgl.Map> = new Map();
private _lastCreatedMap: mapboxgl.Map | undefined;
private _resolves: MapRegisterCallback[] = [];
async waitForMap(): Promise<mapboxgl.Map> {
if (this._lastCreatedMap) {
return this._lastCreatedMap;
} else {
return new Promise((resolve, reject) => {
this._resolves.push(resolve);
});
}
}
private _styleFlushed = false;
private _flushCallbacksWithMap(map: mapboxgl.Map) {
if (this._styleFlushed) {
return;
}
this._styleFlushed = true;
const callbacks: MapRegisterCallback[] = [...this._resolves];
this._resolves.length = 0;
for (const c of callbacks) {
c(map);
}
}
createMap(options: CreateMapboxMapOptions) {
const {camera, container, scene, renderFunc, viewer} = options;
this._scene = scene;
const coreObjectClass = coreObjectClassFactory(camera);
const style = coreObjectClass.attribValue(camera, MapboxCameraAttribute.STYLE) as string;
const longitude = coreObjectClass.attribValue(camera, MapboxCameraAttribute.LONGITUDE) as number;
const latitude = coreObjectClass.attribValue(camera, MapboxCameraAttribute.LATITUDE) as number;
const zoom = coreObjectClass.attribValue(camera, MapboxCameraAttribute.ZOOM) as number;
const minZoom = coreObjectClass.attribValue(camera, MapboxCameraAttribute.MIN_ZOOM) as number;
const maxZoom = coreObjectClass.attribValue(camera, MapboxCameraAttribute.MAX_ZOOM) as number;
const pitch = coreObjectClass.attribValue(camera, MapboxCameraAttribute.PITCH) as number;
const bearing = coreObjectClass.attribValue(camera, MapboxCameraAttribute.BEARING) as number;
const allowDragRotate = coreObjectClass.attribValue(camera, MapboxCameraAttribute.ALLOW_DRAG_ROTATE) as boolean;
const addZoomControl = coreObjectClass.attribValue(camera, MapboxCameraAttribute.ADD_ZOOM_CONTROL) as boolean;
const tlayerBuildings = coreObjectClass.attribValue(camera, MapboxCameraAttribute.LAYER_BUILDINGS) as boolean;
const tlayer3D = coreObjectClass.attribValue(camera, MapboxCameraAttribute.LAYER_3D) as boolean;
const tlayerSky = coreObjectClass.attribValue(camera, MapboxCameraAttribute.LAYER_SKY) as boolean;
const mapOptions: mapboxgl.MapboxOptions = {
style,
container,
center: [longitude, latitude],
zoom,
minZoom,
maxZoom,
pitch,
bearing,
// preserveDrawingBuffer: true,
dragRotate: allowDragRotate,
pitchWithRotate: allowDragRotate,
antialias: true,
interactive: true,
// useWebGL2: true,
};
// webgl2 required since three 150 addition of textureLod in common.glsl
(mapOptions as any).useWebGL2 = true;
const map = new mapboxgl.Map(mapOptions);
const layersOptions: LayersOptions = {
map,
scene,
camera,
renderFunc,
viewer,
lngLat: {
lng: longitude,
lat: latitude,
},
displayScene: scene.threejsScene(),
zoomControls: addZoomControl,
layer3D: tlayer3D,
layerBuildings: tlayerBuildings,
layerSky: tlayerSky,
};
const layersController = new MapboxLayersController(layersOptions);
map.on('load', () => {
layersController.addLayers();
// this.mapboxEventController.camera_node_move_end(); // to update mapbox planes
globalThis.dispatchEvent(new Event('resize')); // helps making sure it is resized correctly
});
map.on('styledata', () => {
// console.log('A styledata event occurred.', map.isStyleLoaded());
if (map.isStyleLoaded()) {
if (!this._styleFlushed && this._lastCreatedMap) {
this._flushCallbacksWithMap(this._lastCreatedMap);
}
}
});
map.on('move', () => this._dispatchCameraMove(JsType.ON_MAPBOX_CAMERA_MOVE));
map.on('movestart', () => this._dispatchCameraMove(JsType.ON_MAPBOX_CAMERA_MOVE_START));
map.on('moveend', () => this._dispatchCameraMove(JsType.ON_MAPBOX_CAMERA_MOVE_END));
// map.on('styledataloading', () => {
// console.log('A styledataloading event occurred.', map.isStyleLoaded());
// });
// this._updateCameraAttributes();
// this._addRemoveControls(map, container.id);
// this._maps_by_container_id.set(container.id, map);
// this._map_containers_by_container_id.set(container.id, container);
// this._canvases_by_container_id.set(container.id, container.querySelector('canvas')!);
this._mapByCameraName.set(camera.name, map);
this._lastCreatedMap = map;
// if (this._mapByCameraName.size == 1) {
// this._flushCallbacksWithMap(map);
// }
return {map, layersController};
}
private _dispatchCameraMove(
type: JsType.ON_MAPBOX_CAMERA_MOVE | JsType.ON_MAPBOX_CAMERA_MOVE_START | JsType.ON_MAPBOX_CAMERA_MOVE_END
) {
if (!this._scene) {
return;
}
this._scene.threejsScene().traverse((object) => {
this._scene?.actorsManager.triggerEventNodes(object, type);
});
}
}
export const MapboxMapsController = MapboxMapsControllerClass.instance();