@polygonjs/plugin-mapbox
Version:
Mapbox plugin for the 3D engine https://polygonjs.com
399 lines (398 loc) • 12.1 kB
JavaScript
import {
TypedCameraObjNode,
CameraMainCameraParamConfig
} from "@polygonjs/polygonjs/dist/src/engine/nodes/obj/_BaseCamera";
import mapboxgl from "mapbox-gl";
import { CoreMapboxClient } from "../../../core/mapbox/Client";
import { ParamConfig, NodeParamsConfig } from "@polygonjs/polygonjs/dist/src/engine/nodes/utils/params/ParamsConfig";
import { isBooleanTrue } from "@polygonjs/polygonjs/dist/src/core/Type";
import { Poly } from "@polygonjs/polygonjs/dist/src/engine/Poly";
import { MapboxPerspectiveCamera } from "../../../core/mapbox/MapboxPerspectiveCamera";
import { MAPBOX_CAMERA_OBJ_NODE_TYPE, registerMapboxCamera } from "../../../core/mapbox/registerMapboxCamera";
import { NodeContext } from "@polygonjs/polygonjs/dist/src/engine/poly/NodeContext";
import { RopType } from "@polygonjs/polygonjs/dist/src/engine/poly/registers/nodes/types/Rop";
import { CameraCSSRendererSopOperation } from "@polygonjs/polygonjs/dist/src/engine/operations/sop/CameraCSSRenderer";
const PRESETS = {
LONDON: {
style: "mapbox://styles/mapbox/dark-v10",
lngLat: [-0.07956, 51.5146]
},
SAN_FRANCISCO: {
style: "mapbox://styles/mapbox/dark-v10",
lngLat: [-122.4726194, 37.7577627]
},
MOUNTAIN: {
style: "mapbox://styles/mapbox-map-design/ckhqrf2tz0dt119ny6azh975y",
lngLat: [-114.34411, 32.6141]
}
};
const PRESET = PRESETS.LONDON;
class MapboxCameraObjParamConfig extends CameraMainCameraParamConfig(NodeParamsConfig) {
constructor() {
super(...arguments);
this.style = ParamConfig.STRING(PRESET.style, {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_style(node);
}
});
this.lngLat = ParamConfig.VECTOR2(PRESET.lngLat, {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.zoom = ParamConfig.FLOAT(15.55, {
range: [0, 24],
rangeLocked: [true, true],
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.zoomRange = ParamConfig.VECTOR2([0, 24], {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.pitch = ParamConfig.FLOAT(60, {
range: [0, 85],
rangeLocked: [true, true],
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.bearing = ParamConfig.FLOAT(60.373613, {
range: [0, 360],
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.updateParamsFromMap = ParamConfig.BUTTON(null, {
label: "Set Navigation Params as Default",
callback: (node, param) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_params_from_map(node);
}
});
this.allowDragRotate = ParamConfig.BOOLEAN(1, {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.addZoomControl = ParamConfig.BOOLEAN(1, {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_update_nav(node);
}
});
this.tlayerBuildings = ParamConfig.BOOLEAN(0);
this.tlayer3D = ParamConfig.BOOLEAN(0);
this.tlayerSky = ParamConfig.BOOLEAN(0);
this.setCSSRenderer = ParamConfig.BOOLEAN(0, {
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_updateCameraAttributes(node);
}
});
this.CSSRenderer = ParamConfig.NODE_PATH("", {
visibleIf: { setCSSRenderer: 1 },
nodeSelection: {
context: NodeContext.ROP,
types: [RopType.CSS2D, RopType.CSS3D]
},
dependentOnFoundNode: true,
callback: (node) => {
MapboxCameraObjNode.PARAM_CALLBACK_updateCameraAttributes(node);
}
});
}
}
const ParamsConfig = new MapboxCameraObjParamConfig();
export class MapboxCameraObjNode extends TypedCameraObjNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this._maps_by_container_id = /* @__PURE__ */ new Map();
this._map_containers_by_container_id = /* @__PURE__ */ new Map();
this._canvases_by_container_id = /* @__PURE__ */ new Map();
this._controls_by_container_id = /* @__PURE__ */ new Map();
this._moving_maps = false;
}
static type() {
return MAPBOX_CAMERA_OBJ_NODE_TYPE;
}
integration_data() {
return CoreMapboxClient.integration_data();
}
createObject() {
return new MapboxPerspectiveCamera();
}
async cook() {
this.updateMaps();
this._updateCameraAttributes();
this.cookController.endCook();
}
static PARAM_CALLBACK_updateCameraAttributes(node) {
node._updateCameraAttributes();
}
_updateCameraAttributes() {
const objects = [this._object];
const node = this;
CameraCSSRendererSopOperation.updateObject({
objects,
params: { node: this.pv.CSSRenderer },
node,
active: this.pv.setCSSRenderer
});
}
createMap(container) {
const map = new mapboxgl.Map({
style: this.pv.style,
container,
center: this.pv.lngLat.toArray(),
zoom: this.pv.zoom,
minZoom: this.pv.zoomRange.x,
maxZoom: this.pv.zoomRange.y,
pitch: this.pv.pitch,
bearing: this.pv.bearing,
dragRotate: this.pv.allowDragRotate,
pitchWithRotate: this.pv.allowDragRotate,
antialias: true
});
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"));
return map;
}
updateMaps() {
this._maps_by_container_id.forEach((map, container_id) => {
this.updateMapFromContainerId(container_id);
});
this._updateCameraAttributes();
}
updateMapFromContainerId(container_id) {
const map = this._maps_by_container_id.get(container_id);
if (!map) {
return;
}
this.updateMapNav(map);
this._addRemoveControls(map, container_id);
map.setStyle(this.pv.style);
}
updateMapNav(map) {
map.jumpTo(this.cameraOptionsFromParams());
map.setMinZoom(this.pv.zoomRange.x);
map.setMaxZoom(this.pv.zoomRange.y);
const drag_rotate_handler = map.dragRotate;
if (isBooleanTrue(this.pv.allowDragRotate)) {
drag_rotate_handler.enable();
} else {
drag_rotate_handler.disable();
}
}
firstMap() {
let first_map;
this._maps_by_container_id.forEach((map, id) => {
if (!first_map) {
first_map = map;
}
});
return first_map;
}
firstId() {
let first_id;
this._maps_by_container_id.forEach((map, id) => {
if (!first_id) {
first_id = id;
}
});
return first_id;
}
firstMapElement() {
const id = this.firstId();
if (id) {
return this._map_containers_by_container_id.get(id);
}
}
bounds() {
const map = this.firstMap();
if (map) {
return map.getBounds();
}
}
zoom() {
const map = this.firstMap();
if (map) {
return map.getZoom();
}
}
center() {
const map = this.firstMap();
if (map) {
return map.getCenter();
}
}
horizontal_lng_lat_points() {
const id = this.firstId();
if (id) {
const map = this._maps_by_container_id.get(id);
const element = this._canvases_by_container_id.get(id);
if (map && element) {
const y = element.clientHeight / 2;
return [map.unproject([0, y]), map.unproject([100, y])];
}
}
}
centerLngLatPoint() {
const id = this.firstId();
if (id) {
const map = this._maps_by_container_id.get(id);
const element = this._canvases_by_container_id.get(id);
if (map && element) {
const x = element.clientWidth * 0.5;
const y = element.clientHeight * 0.5;
return map.unproject([x, y]);
}
}
}
verticalFarLngLatPoints() {
const id = this.firstId();
if (id) {
const map = this._maps_by_container_id.get(id);
const element = this._canvases_by_container_id.get(id);
if (map && element) {
const x = element.clientWidth;
const y = 0;
return [map.unproject([0, y]), map.unproject([x, y])];
}
}
}
verticalNearLngLatPoints() {
const id = this.firstId();
if (id) {
const map = this._maps_by_container_id.get(id);
const element = this._canvases_by_container_id.get(id);
if (map && element) {
const x = element.clientWidth;
const y = element.clientHeight;
return [map.unproject([0, y]), map.unproject([x, y])];
}
}
}
removeMap(container) {
if (container) {
const map = this._maps_by_container_id.get(container.id);
if (map) {
map.remove();
this._maps_by_container_id.delete(container.id);
this._map_containers_by_container_id.delete(container.id);
this._canvases_by_container_id.delete(container.id);
this._controls_by_container_id.delete(container.id);
}
}
}
onMoveEnd(container) {
if (this._moving_maps === true) {
return;
}
this._moving_maps = true;
if (container != null) {
const triggering_map = this._maps_by_container_id.get(container.id);
if (triggering_map != null) {
const camera_options = this.cameraOptionsFromMap(triggering_map);
this._maps_by_container_id.forEach((map, container_id) => {
if (container_id !== container.id) {
const map2 = this._maps_by_container_id.get(container_id);
map2 == null ? void 0 : map2.jumpTo(camera_options);
}
});
}
}
this.object.dispatchEvent({ type: "moveend" });
this._moving_maps = false;
}
lngLat() {
const val = this.pv.lngLat;
return {
lng: val.x,
lat: val.y
};
}
cameraOptionsFromParams() {
return {
center: this.lngLat(),
pitch: this.pv.pitch,
bearing: this.pv.bearing,
zoom: this.pv.zoom
};
}
cameraOptionsFromMap(map) {
return {
center: map.getCenter(),
pitch: map.getPitch(),
bearing: map.getBearing(),
zoom: map.getZoom()
};
}
_addRemoveControls(map, container_id) {
let nav_control = this._controls_by_container_id.get(container_id);
if (nav_control) {
if (!isBooleanTrue(this.pv.addZoomControl)) {
map.removeControl(nav_control);
this._controls_by_container_id.delete(container_id);
}
} else {
if (isBooleanTrue(this.pv.addZoomControl)) {
nav_control = new mapboxgl.NavigationControl();
map.addControl(nav_control, "bottom-right");
this._controls_by_container_id.set(container_id, nav_control);
}
}
}
updateParamsFromMap() {
const map = this.firstMap();
if (map) {
const center = map.getCenter();
const zoom = map.getZoom();
const pitch = map.getPitch();
const bearing = map.getBearing();
this.p.lngLat.set([center.lng, center.lat]);
this.p.zoom.set(zoom);
this.p.pitch.set(pitch);
this.p.bearing.set(bearing);
}
}
static PARAM_CALLBACK_update_params_from_map(node) {
node.updateParamsFromMap();
}
static PARAM_CALLBACK_update_style(node) {
node.updateStyle();
}
static PARAM_CALLBACK_update_nav(node) {
node.updateNav();
}
updateStyle() {
this._maps_by_container_id.forEach((map, container_id) => {
map.setStyle(this.pv.style);
});
}
updateNav() {
this._maps_by_container_id.forEach((map) => {
this.updateMapNav(map);
});
}
async createViewer(options) {
const viewer = Poly.camerasRegister.createViewer({
camera: this.object,
scene: this.scene()
});
let element;
if (options && options instanceof HTMLElement) {
element = options;
} else {
element = options == null ? void 0 : options.element;
}
if (viewer && element) {
viewer.mount(element);
}
return viewer;
}
}
MapboxCameraObjNode.onRegister = registerMapboxCamera;